线段树多种更新+多种查询
三种更新需要三个懒惰标记保存,三种懒惰标记会相互影响,处理比较复杂
对于三种查询用三个数组保存值,更新时需要计算一下公式
这道题满满的都是细心操作啊,写起来很繁琐,我WA无数次后才过了,数组最好都开long long,防止溢出错误
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=100000+100; //数组大小
const ll mod=10007;
ll add[maxn<<2],mul[maxn<<2],cha[maxn<<2]; //懒惰标记
ll sum[maxn<<2],sum2[maxn<<2],sum3[maxn<<2];
int n,m,a,b,c,d;
void PushDown(int rt,ll m);
void change(int rt,ll m,ll c,int f)
{
ll c2=c*c%mod;
ll c3=c2*c%mod;
if(f==1)
{
sum3[rt]=(sum3[rt]+3*sum2[rt]%mod*c%mod+3*sum[rt]%mod*c2%mod+c3*m%mod)%mod;
sum2[rt]=(sum2[rt]+2*sum[rt]*c%mod+c2*m%mod)%mod;
sum[rt]=(sum[rt]+c*m%mod)%mod;
add[rt]=(add[rt]+c)%mod;
}
else if(f==2)
{
sum3[rt]=sum3[rt]*c3%mod;
sum2[rt]=sum2[rt]*c2%mod;
sum[rt]=sum[rt]*c%mod;
mul[rt]=mul[rt]*c%mod;
add[rt]=add[rt]*c%mod;
}
else if(f==3)
{
sum[rt]=c*m%mod;
sum2[rt]=c2*m%mod;
sum3[rt]=c3*m%mod;
cha[rt]=c;
add[rt]=0;
mul[rt]=1;
}
}
void PushUp(int rt)
{
sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
sum2[rt]=(sum2[rt<<1]+sum2[rt<<1|1])%mod;
sum3[rt]=(sum3[rt<<1]+sum3[rt<<1|1])%mod;
}
void PushDown(int rt,ll m) //向下更新
{
if(cha[rt]!=0)
{
ll ml=m%2==0?(m>>1):(m>>1)+1;
change(rt<<1,ml,cha[rt],3);
change(rt<<1|1,m-ml,cha[rt],3);
cha[rt]=0;
}
if(mul[rt]!=1)
{
ll ml=m%2==0?(m>>1):(m>>1)+1;
change(rt<<1,ml,mul[rt],2);
change(rt<<1|1,m-ml,mul[rt],2);
mul[rt]=1;
}
if(add[rt]!=0)
{
ll ml=m%2==0?(m>>1):(m>>1)+1;
change(rt<<1,ml,add[rt],1);
change(rt<<1|1,m-ml,add[rt],1);
add[rt]=0;
}
}
void build(int l,int r,int rt) //建树
{
add[rt]=cha[rt]=0;
mul[rt]=1;
if(l==r)
{
sum[rt]=sum2[rt]=sum3[rt]=0;
return;
}
ll m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
PushUp(rt);
}
void update(int L,int R,ll c,int l,int r,int rt,int f)
{
if(L<=l&&R>=r)
{
ll m=r-l+1;
change(rt,m,c,f);
return;
}
if(l==r) return;
PushDown(rt,r-l+1);
ll m=(l+r)>>1;
if(L<=m) update(L,R,c,l,m,rt<<1,f);
if(m<R) update(L,R,c,m+1,r,rt<<1|1,f);
PushUp(rt);
}
ll query(int L,int R,int l,int r,int rt,int f)
{
if(L<=l&&R>=r)
{
if(f==1) return sum[rt];
if(f==2) return sum2[rt];
if(f==3) return sum3[rt];
}
PushDown(rt,r-l+1);
ll m=(l+r)>>1;
ll ret=0;
if(L<=m) ret+=query(L,R,l,m,rt<<1,f);
if(m<R) ret+=query(L,R,m+1,r,rt<<1|1,f);
ret%=mod;
return ret;
}
int main()
{
//freopen("/home/zlwang/test.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
build(1,n,1);
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
if(a==4)
{
printf("%lld\n",query(b,c,1,n,1,d));
}
else
{
update(b,c,d,1,n,1,a);
}
}
}
return 0;
}