BZOJ1500[NOI2005]維修數列——非旋轉treap
阿新 • • 發佈:2018-06-23
char emp height src alt 格式 == bzoj https
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
10
1
10
題目描述
請寫一個程序,要求維護一個數列,支持以下 6 種操作: 請註意,格式欄 中的下劃線‘ _ ’表示實際輸入文件中的空格輸入
輸入的第1 行包含兩個數N 和M(M ≤20 000),N 表示初始時數列中數的個數,M表示要進行的操作數目。
第2行包含N個數字,描述初始時的數列。
以下M行,每行一條命令,格式參見問題描述中的表格。
任何時刻數列中最多含有500 000個數,數列中任何一個數字均在[-1 000, 1 000]內。
插入的數字總數不超過4 000 000個,輸入文件大小不超過20MBytes。
輸出
對於輸入數據中的GET-SUM和MAX-SUM操作,向輸出文件依次打印結果,每個答案(數字)占一行。
樣例輸入
9 82 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
樣例輸出
-110
1
10
提示
這道題的區間操作十分全,無論是用非旋轉treap還是splay寫,都會有更深入的理解。
講一下每個操作的實現
1、將插入的數再建一棵treap,然後把原treap斷裂,把新建treap合並進去。
2、把treap斷裂成三部分,然後再把左右兩部分合並。
3、也是把treap斷裂成三部分,把中間部分打標記,與線段樹不同的是標記打上就要下傳而不是等到查詢再下傳。
4、和上面一樣,也是斷裂成三部分,中間打標記。
5、斷裂成三部分,輸出中間部分根節點的子樹和。
6、直接輸出根節點的最大連續子段和。
最後不要忘了資源回收(回收節點編號)
最後附上代碼(有註釋)
#include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int num; int pos; int tot;//樹的大小 int root;//根節點 int n,k,g; int x,y,z; int b,c,d; char ch[5]; queue<int>q;//資源回收隊列 int a[200010];//插入序列及初始序列 int m[500010];//區間最大子段和 int s[500010];//翻轉標記 int f[500010];//修改標記 int r[500010];//隨機數 int ls[500010];//左兒子 int rs[500010];//右兒子 int lm[500010];//子樹區間中從左端點開始的最大連續子段和 int rm[500010];//子樹區間中以右端點結束的最大連續子段和 int val[500010];//節點權值 int sum[500010];//子樹區間和 int size[500010];//子樹大小 int INF=2147483647; int insert(int v) { int x; if(!q.empty()) { x=q.front(); q.pop(); } else { x=++tot; } size[x]=1; ls[x]=rs[x]=s[x]=0; f[x]=INF; r[x]=rand(); val[x]=sum[x]=v; lm[x]=rm[x]=m[x]=v; return x; } void updata(int x) { if(!x) { return ; } size[x]=size[ls[x]]+size[rs[x]]+1; sum[x]=sum[ls[x]]+sum[rs[x]]+val[x]; m[x]=max(max(0,rm[ls[x]])+val[x]+max(0,lm[rs[x]]),max(m[ls[x]],m[rs[x]])); lm[x]=max(lm[ls[x]],sum[ls[x]]+val[x]+max(0,lm[rs[x]])); rm[x]=max(rm[rs[x]],sum[rs[x]]+val[x]+max(0,rm[ls[x]])); } void change(int x,int v) { val[x]=v; sum[x]=size[x]*v; lm[x]=rm[x]=max(0,sum[x]); m[x]=max(val[x],sum[x]); f[x]=v; } void rotate(int x) { swap(ls[x],rs[x]); swap(lm[x],rm[x]); s[x]^=1; } void downdata(int x) { if(s[x]) { if(ls[x]) { rotate(ls[x]); } if(rs[x]) { rotate(rs[x]); } } if(f[x]!=INF) { if(ls[x]) { change(ls[x],f[x]); } if(rs[x]) { change(rs[x],f[x]); } } s[x]=0; f[x]=INF; } int build(int l,int r) { if(l>r) { return 0; } int mid=(l+r)>>1; int v=a[mid]; int x=insert(v); ls[x]=build(l,mid-1); rs[x]=build(mid+1,r); updata(x); return x; } void split(int now,int t,int &x,int &y) { if(!now) { x=y=0; } else { downdata(now); if(t<=size[ls[now]]) { y=now; split(ls[now],t,x,ls[now]); } else { x=now; split(rs[now],t-size[ls[now]]-1,rs[now],y); } updata(now); } } int merge(int x,int y) { if(!x||!y) { return x+y; } downdata(x); downdata(y); if(r[x]<r[y]) { rs[x]=merge(rs[x],y); updata(x); return x; } else { ls[y]=merge(x,ls[y]); updata(y); return y; } } void inque(int x) { if(!x) { return ; } q.push(x); inque(ls[x]); inque(rs[x]); } int main() { srand(16); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } val[0]=m[0]=-INF; root=build(1,n); while(k--) { scanf("%s",ch); if(ch[0]==‘I‘) { scanf("%d%d",&pos,&num); for(int i=1;i<=num;i++) { scanf("%d",&a[i]); } z=build(1,num); split(root,pos,x,y); root=merge(merge(x,z),y); } else if(ch[0]==‘D‘) { scanf("%d%d",&pos,&num); split(root,pos-1,x,y); split(y,num,b,c); root=merge(x,c); inque(b); } else if(ch[2]==‘K‘) { scanf("%d%d%d",&pos,&num,&g); split(root,pos-1,x,y); split(y,num,b,c); change(b,g); root=merge(x,merge(b,c)); } else if(ch[0]==‘R‘) { scanf("%d%d",&pos,&num); split(root,pos-1,x,y); split(y,num,b,c); rotate(b); root=merge(x,merge(b,c)); } else if(ch[0]==‘G‘) { scanf("%d%d",&pos,&num); split(root,pos-1,x,y); split(y,num,b,c); printf("%d\n",sum[b]); root=merge(x,merge(b,c)); } else { printf("%d\n",m[root]); } } return 0; }
BZOJ1500[NOI2005]維修數列——非旋轉treap