bzoj 1798 维护序列seq
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798
题解:
高级一点的线段树,加上了区间乘法运算,则需要增加一个数组mulv记录乘的因数,在下放更新sumv和addv值的都时候要先乘再加
被蓝书的写法坑了,就一直搞不懂下放和sumv、addv数组的具体用法,导致网上大犇们的程序我基本都看不懂,写完这道题感觉重新学了一遍线段树
1 #include<cstdio> 2 #include<cstring> 3 #define MAXN 400010 4 #define LL long long 5 LL MOD,sumv[MAXN],addv[MAXN],mulv[MAXN]; 6 int n,m,t1,y1,y2,v; 7 void maintain(int o,int len)//下放 8 { 9 int lc=o<<1,rc=(o<<1)+1,M=len>>1; 10 if(mulv[o]!=1||addv[o]) 11 { 12 mulv[lc]=(mulv[lc]*mulv[o])%MOD; 13 mulv[rc]=(mulv[rc]*mulv[o])%MOD; 14 addv[lc]=((addv[lc]*mulv[o])+addv[o])%MOD; 15 addv[rc]=((addv[rc]*mulv[o])+addv[o])%MOD; 16 sumv[lc]=(sumv[lc]*mulv[o]+(len-M)*addv[o])%MOD; 17 sumv[rc]=(sumv[rc]*mulv[o]+M*addv[o])%MOD; 18 } 19 addv[o]=0; 20 mulv[o]=1; 21 } 22 void build(int o,int L,int R) 23 { 24 int lc=o<<1,rc=(o<<1)+1,M=(L+R)/2; 25 if(L==R) 26 { 27 scanf("%lld",&sumv[o]); 28 return; 29 } 30 build(lc,L,M); 31 build(rc,M+1,R); 32 sumv[o]=(sumv[lc]+sumv[rc])%MOD; 33 } 34 void update(int o,int L,int R) 35 { 36 int lc=o<<1,rc=(o<<1)+1,M=(L+R)/2; 37 if(y1<=L&&y2>=R) 38 { 39 if(t1==1) 40 { 41 addv[o]=(addv[o]*v)%MOD; 42 sumv[o]=(sumv[o]*v)%MOD; 43 mulv[o]=(mulv[o]*v)%MOD; 44 } 45 else 46 { 47 addv[o]=(addv[o]+v)%MOD; 48 sumv[o]=(sumv[o]+v*(R-L+1))%MOD; 49 } 50 return; 51 } 52 maintain(o,R-L+1); 53 if(y1<=M)update(lc,L,M); 54 if(y2>M)update(rc,M+1,R); 55 sumv[o]=(sumv[lc]+sumv[rc])%MOD; 56 } 57 LL query(int o,int L,int R) 58 { 59 int lc=o<<1,rc=(o<<1)+1,M=(L+R)>>1; 60 if(y1<=L&&y2>=R)return sumv[o]%MOD; 61 maintain(o,R-L+1); 62 LL ans=0; 63 if(y1<=M)ans=(query(lc,L,M))%MOD; 64 if(y2>M)ans+=(query(rc,M+1,R))%MOD; 65 sumv[o]=(sumv[lc]+sumv[rc])%MOD; 66 return ans%MOD; 67 } 68 int main() 69 { 70 scanf("%d%lld",&n,&MOD); 71 for(int i=1;i<=400009;i++)mulv[i]=1; 72 build(1,1,n); 73 scanf("%d",&m); 74 while(m--) 75 { 76 scanf("%d%d%d",&t1,&y1,&y2); 77 if(t1!=3) 78 { 79 scanf("%d",&v); 80 update(1,1,n); 81 } 82 else printf("%lld\n",query(1,1,n)); 83 } 84 return 0; 85 }