给一列数构成一个环,一个指针初始指向某个位置,两个参数k1,k2。有6种操作:
add x 从指针指向位置开始,连续k2个数分别加上x;
reverse 从指针开始连续k1个数,反转位置.
insert x 在指针指向位置的后面添加一个数x
delete 删除当前指针指向的数
move x x==1时,指针前移一位,x==2时,指针后移一位。
query 输出指针当前指向的数。
明显都是伸展数的基本操作,思路上应该没什么问题,就是写起来各种郁闷-...为了方便先添加两个虚拟节点,表示第一位的左边和最后一位的右边,接下来在这两个节点直接插入。指针指向的节点实质就是伸展树中rang==2的节点,这样在add,reverse的时候,找到最左侧的节点并将其伸展到根,再找到rank为k1+1或者k2+1的节点,伸展到根的下面,这样两节点之间的部分就是要操作的部分。move的话,前移就删掉虚拟首节点下一个节点,再插入到虚拟尾节点的前边,后移也一样。思路挺好想,就是代码写起来太烦了....
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <memory.h>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <map>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=410000+1000;
int pre[maxn],ch[maxn][2];
int size[maxn],key[maxn];
int add[maxn],flip[maxn];
int root,n;
int tot;
int m,p,q,r,t,tt;
int k1,k2;
int a[maxn];
struct splaytree
{
void pushup(int r)
{
size[r]=1+size[ch[r][0]]+size[ch[r][1]];
}
void go_f(int r)
{
flip[r]^=1;
swap(ch[r][0],ch[r][1]);
}
void go_a(int r,int c)
{
add[r]+=c;
key[r]+=c;
}
void pushdown(int r)
{
if (add[r])
{
// key[r]+=add[r];
// add[ch[r][0]]+=add[r];
// add[ch[r][1]]+=add[r];
go_a(ch[r][0],add[r]);
go_a(ch[r][1],add[r]);
add[r]=0;
}
if (flip[r])
{
// flip[ch[r][0]]^=flip[r];
// flip[ch[r][1]]^=flip[r];
// swap(ch[r][0],ch[r][1]);
go_f(ch[r][0]);
go_f(ch[r][1]);
flip[r]=0;
}
}
void rotate(int x,int kind)
{
int y=pre[x];
pushdown(y);
pushdown(x);
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
if (pre[y])
{
ch[pre[y]][ch[pre[y]][1]==y]=x;
}
pre[x]=pre[y];
ch[x][kind]=y;
pre[y]=x;
pushup(y);
pushup(x);
}
void splay(int x,int tgt)
{
pushdown(x);
while(pre[x]!=tgt)
{
int y=pre[x];
pushdown(pre[y]);
pushdown(y);
pushdown(x);
if (pre[pre[x]]==tgt)
{
rotate(x,ch[pre[x]][0]==x);
}
else
{
int kind=ch[pre[y]][0]==y;
if (ch[y][kind]==x)
{
rotate(x,kind^1);
rotate(x,kind);
}
else
{
rotate(y,kind);
rotate(x,kind);
}
}
}
pushup(x);
if (tgt==0) root=x;
}
void select(int k,int tgt)
{
int rt=root;
pushdown(rt);
while(true)
{
if (k<=size[ch[rt][0]]) rt=ch[rt][0];
else if (k==size[ch[rt][0]]+1) break;
else k-=(size[ch[rt][0]]+1),rt=ch[rt][1];
pushdown(rt);
}
splay(rt,tgt);
}
void newnode(int &r,int father,int k)
{
r=++tot;
pre[r]=father;
size[r]=1;
flip[r]=add[r]=0;
key[r]=k;
ch[r][0]=ch[r][1]=0;
}
void build(int l,int r,int &x,int rt)
{
if (l>r) return;
int m=(l+r)>>1;
newnode(x,rt,a[m]);
build(l,m-1,ch[x][0],x);
build(m+1,r,ch[x][1],x);
pushup(x);
}
void init()
{
tot=root=0;
newnode(root,0,0);
newnode(ch[root][1],root,0);
build(0,n-1,ch[ch[root][1]][0],ch[root][1]);
pushup(ch[root][1]);
pushup(root);
}
void Add(int c)
{
select(1,0);
select(k2+2,root);
// add[ch[ch[root][1]][0]]+=c;
go_a(ch[ch[root][1]][0],c);
}
void Filp()
{
select(1,0);
select(k1+2,root);
// flip[ch[ch[root][1]][0]]^=1;
go_f(ch[ch[root][1]][0]);
}
int del(int tp)
{
int &rt=root;
int len=0;
len=size[rt];
int val;
if (tp)
{
select(1,0);
select(3,rt);
val=key[ch[ch[rt][1]][0]];
ch[ch[rt][1]][0]=0;
pushup(ch[rt][1]);
pushup(rt);
}
else
{
select(len-2,0);
select(len,rt);
val=key[ch[ch[rt][1]][0]];
ch[ch[rt][1]][0]=0;
pushup(ch[rt][1]);
pushup(rt);
}
return val;
}
void insert(int val,int pos)
{
int &rt=root;
select(pos,0);
select(pos+1,rt);
newnode(ch[ch[rt][1]][0],ch[rt][1],val);
pushup(ch[rt][1]);
pushup(rt);
}
void move(int tp)
{
int &rt=root;
int val;
int len;
if (tp==2)
{
val=del(1);
len=size[rt];
insert(val,len-1);
}
else
{
val=del(0);
insert(val,1);
}
}
void query()
{
select(2,0);
pushdown(root);
printf("%d\n",key[root]);
}
}spt;
int main()
{
// freopen("in.txt","r",stdin);
int tt=0;
while(scanf("%d%d%d%d",&n,&m,&k1,&k2) && (n && m && k1 && k2))
{
tt++;
printf("Case #%d:\n",tt);
char cmd[20];
int cd;
for (int i=0; i<n; i++)
scanf("%d",&a[i]);
spt.init();
for (int i=1; i<=m; i++)
{
scanf("%s",cmd);
if (cmd[0]=='a')
{
scanf("%d",&cd);
spt.Add(cd);
}
if (cmd[0]=='r')
{
spt.Filp();
}
if (cmd[0]=='i')
{
scanf("%d",&cd);
spt.insert(cd,2);
}
if (cmd[0]=='d')
{
spt.del(1);
}
if (cmd[0]=='m')
{
scanf("%d",&cd);
spt.move(cd);
}
if (cmd[0]=='q')
{
spt.query();
}
}
}
return 0;
}