大白书例题 uva11922
留个splay模板
虚拟节点可以是放个最小的也可以放最大的,两种方法对同一个点会导致名次相差一。
弄一个节点当null确实比较方便
一开始序列转化成树居然可以直接搞出一条链也没问题,这个略屌。
#include <iostream> #include <cstdio> using namespace std; struct Node { Node *ch[2]; int v,s; bool flip; Node(){}; Node(int v,Node* o):v(v) {s=v+1;ch[0]=ch[1]=o;} int cmp(int x) const{ int l_size=ch[0]->s+1; if(x==l_size)return(-1); return (x<l_size)?(0):(1); } void maintain() {s=ch[0]->s+ch[1]->s+1;} void pushdown(){ if(flip){ flip=0; swap(ch[0],ch[1]); ch[0]->flip^=1; ch[1]->flip^=1; } } }; struct SplayTree { Node *root,*null; SplayTree(){ null=new Node; null->ch[0]=null->ch[1]=null; null->v=null->s=null->flip=0; root=null; } ~SplayTree(){ clear(root); delete null; } void build(Node* &o,int n){ //n=0既为最左边的虚拟节点 if(n>=0){ o=new Node(n,null); build(o->ch[0],n-1); } } void rotate(Node* &o,int d){ Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void splay(Node* &o,int k){ o->pushdown(); int d=o->cmp(k); if(d==1) k-=o->ch[0]->s+1; if(d!=-1){ Node* p=o->ch[d]; p->pushdown(); int d2=p->cmp(k); int k2=(d2==0 ? k : k-p->ch[0]->s-1); if(d2!=-1){ splay(p->ch[d2],k2); if(d==d2) rotate(o,d^1); else rotate(o->ch[d],d); } rotate(o,d^1); } //cout<<(o->v)<<"("<<(o->ch[0]->v)<<","<<(o->ch[1]->v)<<")"<<endl; } Node* merge(Node* left,Node* right){ //left should not be NULL splay(left,left->s); left->ch[1]=right; left->maintain(); return left; } void split(Node* o,int k,Node* &left,Node* &right){ splay(o,k); left=o; right=o->ch[1]; o->ch[1]=null; left->maintain(); } void clear(Node* &o) { if(o->ch[0]!=null) clear(o->ch[0]); if(o->ch[1]!=null) clear(o->ch[1]); delete o; o=null; } void print(Node* o) { if(o==null)return; o->pushdown(); print(o->ch[0]); if(o->v>0) printf("%d\n",o->v); print(o->ch[1]); } void process(int a,int b){ //a的名次是a+1 a-1的名次是a //左边序列到名次a Node *lef,*rig,*mid,*t; split(root,a,lef,t); split(t,b-a+1,mid,rig); mid->flip^=1; root=merge(merge(lef,rig),mid); } }; int main() { int n,m,a,b; scanf("%d%d",&n,&m); SplayTree s; s.build(s.root,n); for(int i=0;i<m;++i){ scanf("%d%d",&a,&b); s.process(a,b); } s.print(s.root); return 0; }
http://acm.hdu.edu.cn/showproblem.php?pid=3487
一开始一直WA是因为Node构造函数忘记给filp赋值。
#include <iostream> #include <cstdio> using namespace std; /** * 对于长度不变的序列n是序列的长度,ansCount和n是用来控制输出空格的 * 对于1..n的序列,左右添加了0和n+1作为虚拟节点防止分裂时出现空 * 调用split和splay时要考虑虚拟节点对名次产生的影响 * 其他函数参数中的名次都是原来序列的名次,虚拟节点产生对名次影响的考虑体现在函数实现中 */ int n,ansCount; struct Node { Node *ch[2]; int v,s; bool flip; Node(){}; Node(int v,Node* o):v(v) { flip=0; s=1; ch[0]=ch[1]=o; } int cmp(int x) const{ int l_size=ch[0]->s+1; if(x==l_size)return(-1); return (x<l_size)?(0):(1); } void maintain() {s=ch[0]->s+ch[1]->s+1;} void pushdown(){ if(flip){ flip=0; swap(ch[0],ch[1]); ch[0]->flip^=1; ch[1]->flip^=1; } } void reverse() { flip^=1; } }; struct SplayTree { Node *root,*null; SplayTree(){ null=new Node; null->ch[0]=null->ch[1]=null; null->v=null->s=null->flip=0; root=null; } ~SplayTree(){ clear(root); delete null; } Node* build(int l,int r){ if(l>r) return null; int m=(l+r)>>1; Node* o = new Node(m,null); o->ch[0]=build(l,m-1); o->ch[1]=build(m+1,r); o->maintain(); return o; } void rotate(Node* &o,int d){ Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void splay(Node* &o,int k){ o->pushdown(); int d=o->cmp(k); if(d== 1) k-=o->ch[0]->s+1; if(d!=-1){ Node* p=o->ch[d]; p->pushdown(); int d2=p->cmp(k); int k2=(d2==0 ? k : k-p->ch[0]->s-1); if(d2!=-1){ splay(p->ch[d2],k2); if(d==d2) rotate(o,d^1); else rotate(o->ch[d],d); } rotate(o,d^1); } //cout<<(o->v)<<"("<<(o->ch[0]->v)<<","<<(o->ch[1]->v)<<")"<<endl; } //left should not be NULL Node* merge(Node* left,Node* right){ splay(left,left->s); left->ch[1]=right; left->maintain(); return left; } void split(Node* o,int k,Node* &left,Node* &right){ splay(o,k); left=o; right=o->ch[1]; o->ch[1]=null; left->maintain(); } void clear(Node* &o) { if(o->ch[0]!=null) clear(o->ch[0]); if(o->ch[1]!=null) clear(o->ch[1]); delete o; o=null; } void print(Node* o) { if(o==null)return; o->pushdown(); print(o->ch[0]); if(o->v>0 && o->v<=n) printf("%d%c",o->v," \n"[++ansCount==n]); print(o->ch[1]); } //把名次a到b切下来 Node* cut(int a,int b){ //a的名次是a+1 a-1的名次是a //左边序列到名次a Node *lef,*rig,*mid,*t; split(root,a,lef,t);//考虑到前半截序列多了一个虚拟节点0名字变大了1 split(t,b-a+1,mid,rig);//后半截的前头没有虚拟节点 root=merge(lef,rig); return mid; } //insert after A[rank] void insert(int rank,Node* mid){ Node *lef,*rig; split(root,rank+1,lef,rig);//考虑到前半截序列多了一个虚拟节点0名字变大了1 root=merge(merge(lef,mid),rig); } //翻转名字a到b的元素 void flip(int a,int b){ Node* mid = cut(a,b); mid->reverse(); insert(a-1,mid); /* 写法二 两种写法都可以,时间也差不多 splay(root,a); splay(root->ch[1],b-a+2); root->ch[1]->ch[0]->reverse(); */ } }; int main() { int m,a,b;char flag[10]; while(scanf("%d%d",&n,&m)!=EOF){ if(n==-1 && m==-1)break; SplayTree s; s.root=s.build(0,n+1); for(int i=0;i<m;++i){ int a,b,c; scanf("%s",flag); switch(flag[0]){ case 'C':{ scanf("%d%d%d",&a,&b,&c); Node *mid=s.cut(a,b); s.insert(c,mid); break; } case 'F':{ scanf("%d%d",&a,&b); s.flip(a,b); break; } } //ansCount=0;s.print(s.root); } ansCount=0; s.print(s.root); } return 0; }