题意:
给定一个环,和一个原点,对这个环有以下操作:
add x 操作:从队首开始的的连续k2个数都加上xֵ.
reverse 操作: 从队首开始的连续k1个数都翻转
insert x 操作:在第一个元素与第二个元素之间插入一个xֵ
delete 操作: 删除原点,新原点顺时针移动一下
move 1操作:原点逆时针移动一个
move 2操作: 原点顺时针移动一个
query 操作: 返回原点元素的值
题解:
伸展树的应用:
正常的伸展树是对数列进行操作,而本题可看作是对一个首尾相连的数列进行操作;标记源点的位置,每次add和reverse的时候,只需将源点反转至根节点,把根节点左边的删除,再插入到剩余序列的尾部,然后再进行更新即可。
#include<bits/stdc++.h> using namespace std; const int maxn = 2e5+99; #define keyv ch[ch[root][1]][0] int pre[maxn],sz[maxn],rev[maxn],add[maxn],ch[maxn][2]; int root,tot1,key[maxn]; int tot2,s[maxn]; int tp; int n,q,k1,k2; int a[maxn]; void newnode(int &r,int fa,int k) { if(tot2) r = s[tot2--]; else r = ++tot1; key[r] = k; pre[r] = fa; add[r] = rev[r] = ch[r][0] = ch[r][1] = 0; sz[r] = 1; } void update_rev(int r) { if(!r)return; swap(ch[r][0],ch[r][1]); rev[r]^=1; } void update_add(int r,int v) { if(!r)return; key[r] += v; add[r] += v; } void pushup(int r) { sz[r] = 1 + sz[ch[r][1]]+sz[ch[r][0]]; } void pushdown(int r) { if(add[r]) { update_add(ch[r][0],add[r]); update_add(ch[r][1],add[r]); add[r] = 0; } if(rev[r]) { update_rev(ch[r][0]); update_rev(ch[r][1]); rev[r] = 0; } } void build(int &x,int l,int r,int fa) { if(l>r)return; int mid = (l+r)>>1; newnode(x,fa,a[mid]); build(ch[x][0],l,mid-1,x); build(ch[x][1],mid+1,r,x); pushup(x); } void init() { root = tot1=tot2 = 0; pre[root] = sz[root] = rev[root] = add[root] = key[root] = ch[root][0] = ch[root][1] = 0; newnode(root,0,-1); newnode(ch[root][1],root,-1); for(int i=0;i<n;i++)scanf("%d",a+i); build(keyv,0,n-1,ch[root][1]); pushup(ch[root][1]); pushup(root); } void rotate(int x,int d) { int y = pre[x]; pushdown(y),pushdown(x); ch[y][!d] = ch[x][d]; pre[ch[x][d]] = y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x] = pre[y]; ch[x][d] = y; pre[y] = x; pushup(y); } void splay(int r,int goal) { while(pre[r] != goal) { if(pre[pre[r]]==goal) { rotate(r,ch[pre[r]][0]==r); } else { int y = pre[r]; int d = ch[pre[y]][0] == y; if(ch[y][d]==r) { rotate(r,!d); rotate(r,d); } else { rotate(y,d); rotate(r,d); } } } pushup(r); if(goal==0)root = r; } int getkth(int r,int k) { pushdown(r); //cout<<1; int t = sz[ch[r][0]]+1; if(k==t) return r; else if(k<t)return getkth(ch[r][0],k); else return getkth(ch[r][1],k-t); } void ADD(int x) { splay(tp,0);///删除左边的 int tmp = sz[ch[root][0]]+1; splay(getkth(root,1),0); splay(getkth(root,tmp),root); tmp = keyv; keyv = 0; pushup(ch[root][1]); pushup(root); ///添加至末尾 splay(getkth(root,sz[root]-1),0); keyv = tmp; pre[keyv] = ch[root][1]; pushup(ch[root][1]); pushup(root); ///更新 splay(getkth(root,1),0); splay(getkth(root,k2+2),root); update_add(keyv,x); pushup(ch[root][1]); pushup(root); tp = getkth(root,2); } void REVERSE() { splay(tp,0); int tmp = sz[ch[root][0]]+1; splay(getkth(root,1),0); splay(getkth(root,tmp),root); tmp = keyv; keyv = 0; pushup(ch[root][1]); pushup(root); splay(getkth(root,sz[root]-1),0); keyv = tmp; pre[keyv] = ch[root][1]; pushup(ch[root][1]); pushup(root); splay(getkth(root,1),0); splay(getkth(root,k1+2),root); update_rev(keyv); pushup(ch[root][1]); pushup(root); tp = getkth(root,2); } void insert(int x) { splay(tp,0); int t = sz[ch[root][0]]+2; splay(getkth(root,t),root); newnode(keyv,ch[root][1],x); pushup(ch[root][1]); pushup(root); } void DELETE() { splay(tp,0); int tmp = sz[ch[root][0]]; splay(getkth(root,tmp),0); splay(getkth(root,tmp+2),root); s[++tot2] = keyv; keyv = 0; pushup(ch[root][1]); pushup(root); ///给顺时针的下一个 if(tmp+1 == sz[root])tp = getkth(root,2);///右边没了(顺时针没了) else tp = getkth(root,tmp+1); } void MOVE(int x) { if(x==1)///逆时针 { splay(tp,0); int t = sz[ch[root][0]]; if(t==1)t = sz[root]-1;///如果左边没了 tp = getkth(root,t); } else///顺时针 { splay(tp,0); int t = sz[ch[root][0]]+2; if(t == sz[root])t=2;///如果右边没了 tp = getkth(root,t); } } int query() { splay(tp,0); return key[root]; } char op[99]; int x; int main() { int kase = 0; while(cin>>n>>q>>k1>>k2) { if(!n && !q && !k1 && !k2)break; printf("Case #%d:\n",++kase); init(); tp = getkth(root,2); while(q--) { scanf("%s",op); if(op[0] == 'a') { scanf("%d",&x); ADD(x); } else if(op[0] == 'r') { REVERSE(); } else if(op[0]=='i') { scanf("%d",&x); insert(x); } else if(op[0] == 'd') DELETE(); else if(op[0]=='m') { scanf("%d",&x); MOVE(x); } else printf("%d\n",query()); } } }