题解 SP4487 【GSS6 - Can you answer these queries VI】

xukuan

2020-05-03 16:28:12

Solution

本题解是[这一篇题解](https://www.luogu.com.cn/blog/xukuan/solution-p2042)的弱化版,采用相同的风格叙述 本题共有6种操作:单点插入,单点删除,单点修改,区间最大子段和 考虑fhqtreap或splay解法,本题解使用fhqtreap **operation 1 单点插入** 以pos位置为界分裂成x,y两段,然后新建一颗树并合并回去 伪代码: ```cpp split(root,pos,x,y) init(a) root=merge(x,merge(New(a)),y) ``` **operation 2 单点删除** 以pos-1和pos为界分裂成x,y,z三段,然后把x,z合并回去 伪代码: ```cpp split(root,pos-1,x,y) split(y,1,y,z) root=merge(x,z) ``` **operation 3 单点修改** 删了再加回去 伪代码: ```cpp split(root,pos-1,x,y) split(y,1,y,z) init(a) cover(y,a) root=merge(x,y),z) ``` **operation 4 区间最大子序列** 以l-1和r为界分裂成x,y,z三段,给区间y算最大子序列(不会的去做SPOJ GSS3),然后把x,y,z合并回去 伪代码: ```cpp split(root,l-1,x,y) split(y,r-l+1,y,z) write(tree[y].sum) root=merge(x,merge(y,z)) ``` 看split和merge两个操作,我们现在要处理pushup和pushdown,另外还有cover和reverse要处理 **关于pushup:** pushup需要传这几个量: 子树大小和维护区间最大子段和所需的四个量。 **关于建树** 仿照线段树的二分建树即可 代码: ```cpp #include<bits/stdc++.h> #include<iostream> #include<cstdio> #define ll long long using namespace std; const ll N=500010; ll n,m,root,cnt,a[N],top,st[N]; struct fhqtreap{ ll lson,rson,rev,cov,size,val,sum,Lmax,Rmax,Mmax,tag,rnd; }tree[N]; inline ll read(){ ll x=0,tmp=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') tmp=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } return tmp*x; } inline void write(ll x){ if(x<0){ putchar('-'); x=-x; } ll y=10,len=1; while(y<=x){ y=(y<<3)+(y<<1); len++; } while(len--){ y/=10; putchar(x/y+48); x%=y; } } inline ll New(ll val){ ll p=st[top--]; tree[p].rnd=rand(); tree[p].lson=tree[p].rson=tree[p].rev=tree[p].cov=0; tree[p].size=1; tree[p].val=tree[p].sum=tree[p].Mmax=val; tree[p].Lmax=tree[p].Rmax=max(0ll,val); return p; } inline void pushup(ll p){ tree[p].size=tree[tree[p].lson].size+tree[tree[p].rson].size+1; tree[p].sum=tree[tree[p].lson].sum+tree[tree[p].rson].sum+tree[p].val; tree[p].Lmax=max(max(tree[tree[p].lson].Lmax,tree[tree[p].lson].sum+tree[p].val+tree[tree[p].rson].Lmax),0ll); tree[p].Rmax=max(max(tree[tree[p].rson].Rmax,tree[tree[p].rson].sum+tree[p].val+tree[tree[p].lson].Rmax),0ll); tree[p].Mmax=max(tree[p].val,tree[tree[p].lson].Rmax+tree[p].val+tree[tree[p].rson].Lmax); if(tree[p].lson) tree[p].Mmax=max(tree[p].Mmax,tree[tree[p].lson].Mmax); if(tree[p].rson) tree[p].Mmax=max(tree[p].Mmax,tree[tree[p].rson].Mmax); } inline void reverse(ll p){ swap(tree[p].lson,tree[p].rson); swap(tree[p].Lmax,tree[p].Rmax); tree[p].rev^=1; } inline void cover(ll p,ll val){ tree[p].val=tree[p].cov=val; tree[p].sum=tree[p].size*val; tree[p].Lmax=tree[p].Rmax=max(0ll,tree[p].sum); tree[p].Mmax=max(val,tree[p].sum); tree[p].tag=1; } inline void pushdown(ll p){ if(tree[p].rev){ if(tree[p].lson) reverse(tree[p].lson); if(tree[p].rson) reverse(tree[p].rson); tree[p].rev=0; } if(tree[p].tag){ if(tree[p].lson) cover(tree[p].lson,tree[p].cov); if(tree[p].rson) cover(tree[p].rson,tree[p].cov); tree[p].cov=tree[p].tag=0; } } void split(ll p,ll k,ll &x,ll &y){ if(!p){ x=y=0; return; } pushdown(p); if(tree[tree[p].lson].size+1<=k){ x=p; split(tree[p].rson,k-tree[tree[p].lson].size-1,tree[p].rson,y); } else{ y=p; split(tree[p].lson,k,x,tree[p].lson); } pushup(p); } ll merge(ll x,ll y){ if(!x||!y) return x|y; if(tree[x].rnd<tree[y].rnd){ pushdown(x); tree[x].rson=merge(tree[x].rson,y); pushup(x); return x; } else{ pushdown(y); tree[y].lson=merge(x,tree[y].lson); pushup(y); return y; } } inline ll build(ll l,ll r){ if(l==r) return New(a[l]); ll mid=(l+r)>>1; return merge(build(l,mid),build(mid+1,r)); } void erase(ll p){ st[++top]=p; if(tree[p].lson) erase(tree[p].lson); if(tree[p].rson) erase(tree[p].rson); } int main(){ for(ll i=1; i<=N-10; i++) st[++top]=i; srand(time(NULL)); n=read(); for(ll i=1; i<=n; i++) a[i]=read(); root=build(1,n); m=read(); while(m--){ char op[10]; scanf("%s",op); ll x,y,z; switch(op[0]){ case 'I':{ ll pos=read(),val=read(); split(root,pos-1,x,y); root=merge(merge(x,New(val)),y); break; } case 'D':{ ll pos=read(); split(root,pos-1,x,y); split(y,1,y,z); erase(y); root=merge(x,z); break; } case 'R':{ ll pos=read(),val=read(); split(root,pos-1,x,y); split(y,1,y,z); cover(y,val); root=merge(x,merge(y,z)); break; } case 'Q':{ ll l=read(),r=read(); split(root,l-1,x,y); split(y,r-l+1,y,z); write(tree[y].Mmax); putchar('\n'); root=merge(x,merge(y,z)); break; } default:{ printf("FUCK %s\n",op); break; } } } return 0; } ```