题意:
给定一个环,和一个原点,对这个环有以下操作:
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());}}
}