给一列数构成一个环,一个指针初始指向某个位置,两个参数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; }