【BZOJ】1251: 序列终结者
【题意】给定含有n个0的的数列。
1.区间加值
2.区间翻转
3.区间求最大值
【算法】平衡树(fhq-treap)
需要特别注意的是:
1.使0点对全局无影响并全程保持(例如求max,t[0].mx=-inf)
2.平衡树和线段树的上传区别在于要考虑本身这个点。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100010; struct tree{int l,r,rnd,num,mx,add,delta,sz;}t[maxn*2]; int st[maxn]; int n,m,root; void down(int k){ if(t[k].delta){ swap(t[k].l,t[k].r); if(t[k].l)t[t[k].l].delta^=1; if(t[k].r)t[t[k].r].delta^=1; t[k].delta=0; } if(t[k].add){ int p=t[k].add; if(t[k].l)t[t[k].l].add+=p,t[t[k].l].mx+=p,t[t[k].l].num+=p; if(t[k].r)t[t[k].r].add+=p,t[t[k].r].mx+=p,t[t[k].r].num+=p;//keep 0->0!!! t[k].add=0; } } int max(int a,int b){return a<b?b:a;} void up(int k){//different from sgt! t[k].mx=max(t[k].num,max(t[t[k].l].mx,t[t[k].r].mx)); t[k].sz=1+t[t[k].l].sz+t[t[k].r].sz; } void dfs(int k){ if(!k)return; dfs(t[k].l); dfs(t[k].r); up(k); } void build(){ int top=0; for(int i=1;i<=n;i++){ t[i]=(tree){0,0,rand(),0,0,0,0,1}; while(top&&t[st[top]].rnd>t[i].rnd){ t[st[top]].r=t[i].l; t[i].l=st[top--]; } t[st[top]].r=i; st[++top]=i; } dfs(st[1]); t[0].r=0; t[0].mx=-0x3f3f3f3f;//make 0 no influence root=st[1]; } int merge(int a,int b){ if(!a||!b)return a^b; if(t[a].rnd<t[b].rnd){ down(a); t[a].r=merge(t[a].r,b); up(a); return a; } else{ down(b); t[b].l=merge(a,t[b].l); up(b); return b; } } void split(int k,int &l,int &r,int x){ if(!k)return void(l=r=0); down(k); if(x<t[t[k].l].sz+1){ r=k; split(t[k].l,l,t[k].l,x); } else{ l=k; split(t[k].r,t[k].r,r,x-t[t[k].l].sz-1); } up(k); } void plus(int l,int r,int x){ int a,b,c; split(root,b,c,r); split(b,a,b,l-1); t[b].add+=x;t[b].mx+=x;t[b].num+=x; root=merge(a,b);root=merge(root,c); } void turn(int l,int r){ int a,b,c; split(root,b,c,r);split(b,a,b,l-1); t[b].delta^=1; root=merge(a,b);root=merge(root,c); } int ask(int l,int r){ int a,b,c,ans; split(root,b,c,r);split(b,a,b,l-1); ans=t[b].mx; root=merge(a,b);root=merge(root,c); return ans; } int main(){ srand(233); scanf("%d%d",&n,&m); build(); for(int i=1;i<=m;i++){ int k,l,r,x; scanf("%d%d%d",&k,&l,&r); if(l>r)continue; if(k==1){ scanf("%d",&x); plus(l,r,x); } else if(k==2)turn(l,r); else printf("%d\n",ask(l,r)); } return 0; }