BZOJ1798: [Ahoi2009]Seq 维护序列seq
题目链接:
題解:
线段树玩法真心多233
以前见过类似的题,但没写,今天做LCT发现一道双修改,尴尬的发现自己不太会2333,然后zyf就一脸嫌弃的告诉我先写这道线段树的版本emmmmmmm
自己YY了好久,发现总会被时间顺序日到……看了题解(我是大蒟蒻……
因为我一直都想把两种操作分离开,事实上没必要,因为发现对于已经加过的数值$plus$,假设我们没有将这个值传下去,那么下次修改时,若我们将其乘上一个数$mul$,事实上按照时间顺序,我们其实也要把该值乘上$mul$。所以我们可以直接将$plus$乘上$mul$,等到以后再传下去。这样我们就有效的干掉了时间顺序。
代码:
1 #define Troy 2 3 #include "bits/stdc++.h" 4 5 using namespace std; 6 7 const int N=1e5+5; 8 9 inline int read(){ 10 int s=0,k=1;char ch=getchar(); 11 while(ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar(); 12 while(ch>47&ch<='9') s=s*10+(ch^48),ch=getchar(); 13 return s*k; 14 } 15 16 int n,p,m; 17 18 struct Tree{ 19 int sum,mul,plu; 20 Tree *lc,*rc; 21 Tree(){sum=plu=0,mul=1;lc=rc=NULL;} 22 }*root,tree[N<<2];int cnt; 23 24 inline void build(Tree *&u,int l,int r){ 25 u=tree+cnt,++cnt; 26 if(l==r){ 27 u->sum=read();return; 28 }int mid=l+r>>1; 29 build(u->lc,l,mid); 30 build(u->rc,mid+1,r); 31 u->sum=(u->lc->sum+u->rc->sum)%p; 32 } 33 34 inline void push(Tree *u,int leth,int mul,int plu){ 35 u->sum=(u->sum*1ll*mul+plu*1ll*(leth))%p; 36 u->mul=u->mul*1ll*mul%p; 37 u->plu=(u->plu*1ll*mul+plu)%p; 38 } 39 40 inline void pushdown(Tree *u,int l,int r){ 41 int mid=l+r>>1; 42 push(u->lc,mid-l+1,u->mul,u->plu); 43 push(u->rc,r-mid,u->mul,u->plu); 44 u->mul=1,u->plu=0; 45 } 46 47 inline void update_1(Tree *u,int l,int r,int x,int y,int val){ 48 if(x<=l&&r<=y){ 49 u->mul=(u->mul*1ll*val)%p; 50 u->plu=(u->plu*1ll*val)%p; 51 u->sum=(u->sum*1ll*val)%p; 52 return ; 53 } 54 int mid=l+r>>1; 55 pushdown(u,l,r); 56 if(y>mid) update_1(u->rc,mid+1,r,x,y,val); 57 if(x<=mid) update_1(u->lc,l,mid,x,y,val); 58 u->sum=(u->lc->sum+u->rc->sum)%p; 59 } 60 61 inline void update_2(Tree *u,int l,int r,int x,int y,int val){ 62 if(x<=l&&r<=y){ 63 u->plu=(u->plu*1ll+val)%p; 64 u->sum=(u->sum+1ll*val*(r-l+1))%p; 65 return ; 66 } 67 int mid=l+r>>1; 68 pushdown(u,l,r); 69 if(y>mid) update_2(u->rc,mid+1,r,x,y,val); 70 if(x<=mid) update_2(u->lc,l,mid,x,y,val); 71 u->sum=(u->lc->sum+u->rc->sum)%p; 72 } 73 74 inline int query(Tree *u,int l,int r,int x,int y){ 75 if(x<=l&&r<=y) return u->sum; 76 pushdown(u,l,r); 77 int mid=l+r>>1,ret=0; 78 if(x<=mid) ret=query(u->lc,l,mid,x,y); 79 if(y>mid) ret=(ret+query(u->rc,mid+1,r,x,y))%p; 80 return ret; 81 } 82 83 int main(){ 84 n=read(),p=read(); 85 build(root,1,n); 86 m=read()+1; 87 register int opt,x,y,val; 88 while(--m){ 89 opt=read(); 90 x=read(),y=read(); 91 if(opt!=3) val=read()%p; 92 switch(opt){ 93 case 1:update_1(root,1,n,x,y,val);break; 94 case 2:update_2(root,1,n,x,y,val);break; 95 case 3:printf("%d\n",query(root,1,n,x,y)); 96 } 97 } 98 }
没有什么不可能。