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