题目有很多图,不好粘贴。。。。。
题意:给出N个数和K1,K2的值,最开始指针指向第一个数,有6种操作
add x : 给前K2个数都增加x
reverse : 翻转前K1个数
insert x : 在所指的数右边(顺时针)插入一个数
delete x : 删除指针所指的这个数,并且指针向右移(顺时针)
move x : x=1则指向向左移(逆时针),为2向右移(顺时针)
query : 输出指针所指的数
解析:这题涉及到插入删除,和给一段区间加值,线段树不能增加删除,链表的话又不能快速的给一段区间加数,所以只能用伸展树了。伸展树支持的操作很多,既有线段树的特性也有链表的特性。但是写起来复杂,所以一般题目如果能用常用的数据结构解决的就不要用伸展树了。我不具体介绍伸展树,自己下去多学学再看这题会容易许多。
源代码
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; const int INF=1e9+7; const int maxn=200005; int A[maxn],cnt; //A数组保存数,cnt是节点标号,我是用数组模拟的 struct treap { treap* son[2]; //左右儿子 int v,s,add,lazy; //v是值,s是大小,add是懒惰标记增加的值,lazy是懒惰标记是否需要翻转 treap(){ v=s=add=lazy=0; son[0]=son[1]=NULL; } treap(int nv); int rk(){ return son[0]->s+1; } //排名,第几个数 int cmp(int k) //比较,如果相等返回-1,小于返回0,大于1 { if(k==rk()) return -1; return k<rk()?0:1; } void pushup(){ s=son[0]->s+son[1]->s+1; } //更新大小 void pushdown() //处理懒惰标记 { if(lazy) { swap(son[0],son[1]); son[0]->lazy^=1; son[1]->lazy^=1; lazy=0; } if(add) { v+=add; son[0]->add+=add; son[1]->add+=add; add=0; } } }null,tr[maxn]; treap::treap(int nv) { v=nv; s=1; add=lazy=0; son[0]=son[1]=&null; } treap* NewNode(int x) { tr[cnt]=treap(x); return tr+cnt++; } struct splaytree { int Size; treap* root; splaytree(){ Size=0; root=&null; } void Rotate(treap* &t,int d) //翻转操作 { t->pushdown(); treap* p=t->son[d^1]; p->pushdown(); t->son[d^1]=p->son[d]; p->son[d]=t; t->pushup(); t=p; t->pushup(); } void Splay(treap* &t,int k) //将第k大的节点伸展到根 { t->pushdown(); int d=t->cmp(k); if(d!=-1) { if(d) Splay(t->son[d],k- t->rk()); else Splay(t->son[d],k); Rotate(t,d^1); } } void Build(treap* &t,int le,int ri) //将N个数建成一棵树 { if(le>ri) return; int mid=(le+ri)/2; t=NewNode(A[mid]); Build(t->son[0],le,mid-1); Build(t->son[1],mid+1,ri); t->pushup(); } void Add(treap* &t,int k,int a) //加值 { Splay(t,k); t->v+=a; t->son[0]->add+=a; } void Reverse(treap* &t,int k) //翻转 { Splay(t,k); treap* p=t->son[1]; t->son[1]=&null; t->pushup(); t->lazy=1; t->pushdown(); Splay(t,k); t->son[1]=p; t->pushup(); } void Insert(treap* &t,int x) //插入 { Splay(t,1); treap* p=NewNode(x); p->son[1]=t->son[1]; p->pushup(); t->son[1]=p; t->pushup(); Size++; } void Remove(treap* &t) 删除 { Splay(t,1); treap* next=t->son[1]; t=next; t->pushdown(); Size--; } void Move(treap* &t,int x) //移动 { if(x==1) { Splay(t,Size); treap* p=t->son[0]; t->son[0]=&null; p->pushdown(); Splay(p,1); t->son[1]=p; t->pushup(); } else { Splay(t,1); treap* p=t->son[1]; t->son[1]=&null; p->pushdown(); Splay(p,Size-1); t->son[0]=p; t->pushup(); } } }; int N,M,K1,K2; int main() { int Case=0; while(scanf("%d%d%d%d",&N,&M,&K1,&K2)!=EOF) { if(!N&&!M&&!K1&&!K2) break; for(int i=1;i<=N;i++) scanf("%d",&A[i]); cnt=0; splaytree spt; spt.Build(spt.root,1,N); spt.Size=N; printf("Case #%d: ",++Case); while(M--) { char op[10]; int x; scanf("%s",op); if(strcmp(op,"add")==0) { scanf("%d",&x); spt.Add(spt.root,K2,x); } else if(strcmp(op,"reverse")==0) spt.Reverse(spt.root,K1); else if(strcmp(op,"insert")==0) { scanf("%d",&x); spt.Insert(spt.root,x); } else if(strcmp(op,"delete")==0) spt.Remove(spt.root); else if(strcmp(op,"move")==0) { scanf("%d",&x); spt.Move(spt.root,x); } else { spt.Splay(spt.root,1); printf("%d ",spt.root->v); } } } return 0; }