1.子段乘积
直接暴力做肯定超时
用线段树O(nlogn)
数组要开2e+10,如果开2e5+10就会wa(段错误)RE
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e6 + 10;
const ll mod=998244353;
ll n,m,k,arr[N];
struct node
{
ll l,r,sum;
}tree[N];
inline void push_up(ll i)
{
tree[i].sum=(tree[i*2].sum)%mod*(tree[i*2+1].sum)%mod;
}
inline void build(ll i,ll l,ll r)
{
tree[i].l=l,tree[i].r=r;
if(l==r)
{
tree[i].sum=arr[l];
return ;
}
ll mid=(l+r)>>1;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
push_up(i);
}
inline ll query(ll i,ll l,ll r)
{
if(tree[i].l>=l&&tree[i].r<=r)
return tree[i].sum;
ll res=1;
if(tree[i*2].r>=l)
res=(res*query(i*2,l,r))%mod;
if(tree[i*2+1].l<=r)
res=(res*query(i*2+1,l,r))%mod;
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>k;
for(int i=1;i<=n;++i)
cin>>arr[i];
build(1,1,n);
ll ans=0;
for(int i=1;i<=n-k;++i)
{
ans=max(ans,query(1,i,i+k-1));
}
cout<<ans%mod<<endl;
return 0;
}
P3372 【模板】线段树 1(加法线段树)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+7;
const ll mod=2147483647;
ll n,m;
struct node
{
ll l,r,sum,lz;
}tree[N];
ll arr[N];
void build(ll i,ll l,ll r,ll arr[])
{
tree[i].lz=0;//初始化的时候肯定都是0
tree[i].l=l;
tree[i].r=r;
if(l==r)
{
tree[i].sum=arr[l];//到达底部单节点才把输入的值赋给你
return ;
}
ll mid=(l+r)/2;
build(i*2,l,mid,arr);
build(i*2+1,mid+1,r,arr);
tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;//树已经全部建完了,再从下往上+++,使得上层的树都有了值
return ;
}
inline void push_down(ll i)
{
if(tree[i].lz!=0)
{
tree[i*2].lz+=tree[i].lz;
tree[i*2+1].lz+=tree[i].lz;
ll mid=(tree[i].l+tree[i].r)/2;
tree[i*2].sum+=tree[i].lz*(mid-tree[i*2].l+1);
tree[i*2+1].sum+=tree[i].lz*(tree[i*2+1].r-mid);
tree[i].lz=0;
}
return ;
}
inline void add(ll i,ll l,ll r,ll k)
{
if(tree[i].l>=l&&tree[i].r<=r)
{
tree[i].sum+=k*(tree[i].r-tree[i].l+1);
tree[i].lz+=k;
return ;
}
push_down(i);
if(tree[i*2].r>=l)
add(i*2,l,r,k);
if(tree[i*2+1].l<=r)
add(i*2+1,l,r,k);
tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
return ;
}
inline ll searchs(ll i,ll l, ll r)
{
if(tree[i].l>=l&&tree[i].r<=r)
return tree[i].sum;
push_down(i);
ll num=0;
if(tree[i*2].r>=l)
num+=searchs(i*2,l,r);
if(tree[i*2+1].l<=r)
num+=searchs(i*2+1,l,r);
return num;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;++i)
cin>>arr[i];
build(1,1,n,arr);//从根节点开始建树
for(int i=1;i<=m;++i)
{
ll tmp;
cin>>tmp;
if(tmp==1)
{
ll a,b,c;
cin>>a>>b>>c;
add(1,a,b,c);//每次修改都是从编号为1开始的,因为编号1是树的顶端,往下分叉
}
if(tmp==2)
{
ll a,b;
cin>>a>>b;
printf("%lld\n",searchs(1,a,b));//编号i的话,每次都是从1开始
}
}
return 0;
}
P3373 【模板】线段树 2(乘法线段树)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e6+7;
template<typename T>void read(T &x)
{
x=0;char ch=getchar();ll f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}x*=f;
}
ll n,m,arr[N],mod,flag,cn,cm,cw;
struct node
{
ll l,r,sum,mul,add;//有乘有加,先乘后加
}tree[N];
inline void build(ll i,ll l,ll r)
{
tree[i].l=l;
tree[i].r=r;
tree[i].mul=1;
if(l==r)
{
tree[i].sum=arr[l]%mod;
return ;
}
ll mid=(l+r)>>1;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
tree[i].sum=(tree[i*2].sum+tree[i*2+1].sum)%mod;
}
inline void push_down(ll i)
{
tree[i*2].sum=(ll)(tree[i].mul*tree[i*2].sum+((tree[i*2].r-tree[i*2].l+1)*tree[i].add)%mod)%mod;
tree[i*2+1].sum=(ll)(tree[i].mul*tree[i*2+1].sum+((tree[i*2+1].r-tree[i*2+1].l+1)*tree[i].add)%mod)%mod;
tree[i*2].mul=(ll)(tree[i*2].mul*tree[i].mul)%mod;
tree[i*2+1].mul=(ll)(tree[i*2+1].mul*tree[i].mul)%mod;
tree[i*2].add=(ll)(tree[i*2].add*tree[i].mul+tree[i].add)%mod;
tree[i*2+1].add=(ll)(tree[i*2+1].add*tree[i].mul+tree[i].add)%mod;
tree[i].mul=1;tree[i].add=0;
}
inline void add(ll i,ll l,ll r,ll k)
{
if(tree[i].l>=l&&tree[i].r<=r)
{
tree[i].add=(ll)(tree[i].add+k)%mod;
tree[i].sum=(ll)(tree[i].sum+k*(tree[i].r-tree[i].l+1))%mod;
return ;
}
push_down(i);
tree[i].sum=(tree[i*2].sum+tree[i*2+1].sum)%mod;
if(tree[i*2].r>=l)
add(i*2,l,r,k);
if(tree[i*2+1].l<=r)
add(i*2+1,l,r,k);
//ll mid=(tree[i].l+tree[i].r)>>1;
//if(l<=mid)add(i*2,l,r,k);
//if(mid<r)add(i*2+1,l,r,k);
tree[i].sum=(tree[i*2].sum+tree[i*2+1].sum)%mod;
}
inline void mult(ll i,ll l,ll r,ll k)
{
if(tree[i].l>=l&&tree[i].r<=r)
{
tree[i].mul=(tree[i].mul*k)%mod;
tree[i].add=(tree[i].add*k)%mod;
tree[i].sum=(tree[i].sum*k)%mod;
return ;
}
push_down(i);
tree[i].sum=(tree[i*2].sum+tree[i*2+1].sum)%mod;
if(tree[i*2].r>=l)
mult(i*2,l,r,k);
if(tree[i*2+1].l<=r)
mult(i*2+1,l,r,k);
//ll mid=(tree[i].l+tree[i].r)>>1;
//if(l<=mid)mult(i*2,l,r,k);
//if(mid<r)mult(i*2+1,l,r,k);
tree[i].sum=(tree[i*2].sum+tree[i*2+1].sum)%mod;
}
inline ll query(ll i,ll l,ll r)
{
if(tree[i].l>=l&&tree[i].r<=r)
return tree[i].sum;
push_down(i);
ll num=0;
if(tree[i*2].r>=l)
num=(num+query(i*2,l,r))%mod;
if(tree[i*2+1].l<=r)
num=(num+query(i*2+1,l,r))%mod;
return num;
//ll val=0;
//ll mid=(tree[i].l+tree[i].r)>>1;
//if(l<=mid)val=(val+query(i*2,l,r))%mod;
//if(mid<r)val=(val+query(i*2+1,l,r))%mod;
//return val;
}
int main()
{
read(n),read(m),read(mod);
for(int i=1;i<=n;++i)
read(arr[i]);
build(1,1,n);
for(int i=1;i<=m;++i)
{
read(flag);
if(flag==1)
{
read(cn),read(cm),read(cw);
mult(1,cn,cm,cw);
}
else if(flag==2){
read(cn),read(cm),read(cw);
add(1,cn,cm,cw);
}
else {
read(cn),read(cm);
cout<<query(1,cn,cm)<<endl;
}
}
}
P4145 上帝造题的七分钟2 / 花神游历各国(根号线段树)
P4145 上帝造题的七分钟2 / 花神游历各国
这道题的关键在于,sqrt(1)==1
也就是说,如果一个区间的最大值为1,我们就可以直接跳过这段区间的修改。只有最大值大于1时才有修改的必要。
而题中的数值大小范围在(0,1e12)之间。
我们可以用计算器得知:
每个数至多六次开平方便可得到1
每次暴力修改复杂度为logn,总复杂度nlogn。数据范围只有1e5,因此不用在意常数的影响。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 4e5 + 10;
const ll mod=1000000010;
ll n,m,k,arr[N];
struct node
{
ll l,r,sum,maxn;
}tree[N];
inline void push_up(ll i)
{
tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
tree[i].maxn=max(tree[i*2].maxn,tree[i*2+1].maxn);
}
inline void build(ll i,ll l,ll r)
{
tree[i].l=l;
tree[i].r=r;
if(l==r)
{
tree[i].sum=tree[i].maxn=arr[l];
return ;
}
ll mid=(l+r)>>1;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
push_up(i);
}
inline void change(ll i,ll l,ll r)
{
if(tree[i].l==tree[i].r)
{
tree[i].sum=sqrt(tree[i].sum);
tree[i].maxn=sqrt(tree[i].maxn);
return ;
}
if(tree[i*2].r>=l&&tree[i*2].maxn>1)
change(i*2,l,r);
if(tree[i*2+1].l<=r&&tree[i*2+1].maxn>1)
change(i*2+1,l,r);
push_up(i);
}
inline ll query(ll i,ll l,ll r)
{
if(tree[i].l>=l&&tree[i].r<=r)
return tree[i].sum;
ll ans=0;
if(tree[i*2].r>=l)
ans+=query(i*2,l,r);
if(tree[i*2+1].l<=r)
ans+=query(i*2+1,l,r);
return ans;
}
int main()
{
ll a,l,r;
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;++i)
cin>>arr[i];
build(1,1,n);
cin>>m;
while(m--)
{
cin>>a>>l>>r;
if(l>r)swap(l,r);
if(a==0)
change(1,l,r);
else cout<<query(1,l,r)<<endl;
}
return 0;
}