[BZOJ 1500] 维护序列
Link:
Solution:
可能平衡树维护序列的所有操作都在这了吧……
对序列的维护$fhq treap$和$Splay$都能做
有几个注意点:
1、维护序列时始终记得第$k$大指的是序号,与权值无关
2、注意对0的初始化,毕竟如果无叶子结点时会用到
3、如果数据总量过大要数据回收,用队列记录被删除的节点,同时记得将儿子信息初始化!
4、如果求最大子序列和,一般要维护$lmx,rmx$来求解
如果同时还有翻转操作,记得将$lmx$和$rmx$也要翻转!
6、对$Treap$的初始化时并不需要基于随机的旋转操作,直接构造就好了
要明白随机的旋转目的是为了保证期望树高,如果已经构造得最优了自然不必旋转了
Code:
#include <bits/stdc++.h> using namespace std; #define X first #define Y second #define lc s[x][0] #define rc s[x][1] typedef long long ll; typedef pair<int,int> P; const int MAXN=5e5+10,INF=1<<30; char op[20];queue<int> q; int spin[MAXN],cov[MAXN],sum[MAXN],mx[MAXN],lmx[MAXN],rmx[MAXN]; int rt,n,m,num,cnt,dat[MAXN],s[MAXN][2],pri[MAXN],sz[MAXN],val[MAXN]; int newnode(int x) { int cur; if(!q.empty()) cur=q.front(),q.pop(); else cur=++cnt; sz[cur]=1;pri[cur]=rand(); s[cur][0]=s[cur][1]=0;//重用节点后记得清零 val[cur]=sum[cur]=mx[cur]=lmx[cur]=rmx[cur]=x; spin[cur]=0;cov[cur]=INF;return cur; } void rotate(int x) { swap(s[x][0],s[x][1]); swap(lmx[x],rmx[x]);spin[x]^=1; } void modify(int x,int k) {//记得更新所有数据! val[x]=k;cov[x]=k; sum[x]=sz[x]*k; mx[x]=max(sum[x],val[x]); lmx[x]=rmx[x]=max(0,sum[x]); } void pushdown(int x) { if(spin[x]) {if(lc) rotate(lc);if(rc) rotate(rc);} if(cov[x]!=INF) {if(lc) modify(lc,cov[x]);if(rc) modify(rc,cov[x]);} spin[x]=0;cov[x]=INF; } void pushup(int x) { if(!x) return; sz[x]=sz[lc]+sz[rc]+1; sum[x]=sum[lc]+sum[rc]+val[x]; mx[x]=max(mx[lc],mx[rc]); mx[x]=max(mx[x],max(0,rmx[lc])+val[x]+max(0,lmx[rc])); lmx[x]=max(lmx[lc],sum[lc]+val[x]+max(0,lmx[rc])); rmx[x]=max(rmx[rc],sum[rc]+val[x]+max(0,rmx[lc])); } int build(int l,int r) { if(l>r) return 0; int mid=(l+r)>>1; int x=newnode(dat[mid]); s[x][0]=build(l,mid-1); s[x][1]=build(mid+1,r); pushup(x);return x; } void split(int x,int k,int &a,int &b) { if(!x){a=b=0;return;} pushdown(x); if(k<=sz[lc]) b=x,split(lc,k,a,lc); else a=x,split(rc,k-sz[lc]-1,rc,b); pushup(x); } int merge(int x,int y) { if(!x||!y) return x+y; pushdown(x);pushdown(y); if(pri[x]<pri[y]) { s[x][1]=merge(s[x][1],y); pushup(x);return x; } else { s[y][0]=merge(x,s[y][0]); pushup(y);return y; } } void reuse(int x) {//记录重用节点 if(!x) return; q.push(x); reuse(lc);reuse(rc); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&dat[i]); mx[0]=val[0]=-INF;rt=build(1,n); int num,pos,k,x,y,z; for(int i=1;i<=m;i++) { scanf("%s",op+1); if(op[3]!='X') scanf("%d%d",&pos,&num); if(op[1]=='I') { for(int j=1;j<=num;j++) scanf("%d",&dat[j]); z=build(1,num); split(rt,pos,x,y); rt=merge(x,merge(z,y)); } else if(op[1]=='D') { split(rt,pos-1,x,y); split(y,num,y,z); reuse(y);rt=merge(x,z); } else if(op[3]=='K') { scanf("%d",&k); split(rt,pos-1,x,y); split(y,num,y,z); modify(y,k); rt=merge(x,merge(y,z)); } else if(op[1]=='R') { split(rt,pos-1,x,y); split(y,num,y,z);rotate(y); rt=merge(x,merge(y,z)); } else if(op[1]=='G') { split(rt,pos-1,x,y); split(y,num,y,z); printf("%d\n",sum[y]); rt=merge(x,merge(y,z)); } else printf("%d\n",mx[rt]); } return 0; }