Splay基本操作:
1.rotate() 旋转操作---包含三种情况
2.splay() 伸展-----一般是旋到根或根的父亲的下面
3.rotate_to() 先找到要伸展的结点,再splay;
4.push_up() 向上维护根的信息
5.push_down()向下下放延迟标记
6.Cut() 删除一个区间
7.insert()插入一个区间
8.Flip()翻转一个区间
9.pred()求结点的前驱
10.succ()求结点的后继
11.dfs()中序遍历---为了输出序列.
12.built()二分建树
13.New_Node()新建结点--如果多个函数要用到则写,否则不用!
poj3468--其它数据结构也可以实现!
//12344261 3468 Accepted 4468K 2907MS C++ 3222B 2013-12-01 11:37:06 #include <iostream> #include<cstdio> using namespace std; #define MAX 100010 #define bint __int64 int N,Q,tot; int A[MAX]; struct Node { int size,vol,add; bint sum; Node*d[2]; Node*pre; }*Null,*root,space[MAX]; void updata(Node*p) { p->size=p->d[0]->size+p->d[1]->size+1; p->sum=p->d[0]->sum+p->d[1]->sum+p->vol; } void Push_down(Node*x) { if(x==Null) return; x->vol+=x->add; x->d[0]->add+=x->add; x->d[1]->add+=x->add; if(x->d[0]!=Null) x->d[0]->sum+=(bint)(x->add)*(x->d[0]->size); if(x->d[1]!=Null) x->d[1]->sum+=(bint)(x->add)*(x->d[1]->size); x->add=0; } void Rotate(Node*x,int c) { Node*y=x->pre; Push_down(y),Push_down(x); y->d[!c]=x->d[c],x->pre=y->pre; if(x->d[c]!=Null) x->d[c]->pre=y; if(y->pre!=Null) y->pre->d[y->pre->d[1]==y]=x; y->pre=x,x->d[c]=y; if(root==y) root=x; updata(y); } void Splay(Node*x,Node*f) { for(Push_down(x);x->pre!=f;) { if(x->pre->pre==f) Rotate(x,x->pre->d[0]==x); else { Node *y=x->pre , *z=y->pre; if(z->d[0]==y) if(y->d[0]==x) Rotate(y,1),Rotate(x,1); else Rotate(x,0),Rotate(x,1); else if(y->d[1]==x) Rotate(y,0),Rotate(x,0); else Rotate(x,1),Rotate(x,0); } } updata(x); } Node* New_Node(int x) { Node*p=&space[tot++]; p->d[0]=p->d[1]=p->pre=Null; p->add=0; p->size=1; p->sum=p->vol=x; return p; } Node* Make_Tree(int l,int r,Node* fa) { if(l>r) return Null; int m=(l+r)>>1; Node*p=New_Node(A[m]); p->d[0]=Make_Tree(l,m-1,p); p->d[1]=Make_Tree(m+1,r,p); p->pre=fa; updata(p); return p; } void init() { tot=0; Null=New_Node(0); Null->size=0; root=New_Node(-1); root->d[1]=New_Node(-1); root->d[1]->pre=root; updata(root); root->d[1]->d[0]=Make_Tree(1,N,root->d[1]); } void Select(int k,Node*f) { Node*p=root; while(true) { Push_down(p); int tem=p->d[0]->size; if(k==tem+1) break; if(k <= tem) p=p->d[0]; else p=p->d[1],k-=tem+1; } Splay(p,f); } int main() { while(~scanf("%d%d",&N,&Q)) { for(int i=1;i<=N;i++) scanf("%d",&A[i]); init(); char op[2]; for(int i=1;i<=Q;i++) { scanf("%s",op); if(op[0]=='C') { int a,b,c; scanf("%d%d%d",&a,&b,&c); Select(a,Null); Select(b+2,root); root->d[1]->d[0]->add+=c; root->d[1]->d[0]->sum+=(bint)c*(root->d[1]->d[0]->size); } else { int a,b; scanf("%d%d",&a,&b); Select(a,Null); Select(b+2,root); printf("%I64d\n",root->d[1]->d[0]->sum); } } } return 0; }
hdu4441---指定位置插入(最好用splay)
//9740664 2013-12-02 22:21:47 Accepted 4441 1140MS 9464K 3860 B G++ #include<cstdio> #include<queue> #include<vector> #include<cstring> #include<iostream> using namespace std; #define Stype(x) (ns[ns[x].f].son[1]==x) typedef __int64 ll; const int N = 100005; int m;int posn[N],posp[N]; struct Splay { int nns,begin,end; struct node{int size,key,f,son[2]; ll sum; bool p;}ns[2*N]; inline int operator[](int x){return ns[x].key;} inline int NewNode(int x,int f) { ns[++nns].key=ns[nns].sum=x; ns[nns].size=1; ns[nns].f=f; ns[nns].p=x>0; return nns; } inline void init() { nns=0; memset(ns,0,sizeof(ns)); begin=ns[0].son[0]=NewNode(0,0); end=ns[1].son[1]=NewNode(0,1); Updata(1); } inline void Updata(int x) { ns[x].sum=ns[ns[x].son[0]].sum+ns[ns[x].son[1]].sum+ns[x].key; ns[x].size=ns[ns[x].son[0]].size+ns[ns[x].son[1]].size+1; ns[x].p=ns[x].key>0 || ns[ns[x].son[0]].p || ns[ns[x].son[1]].p; } int pred(int x) { splay(x); for(x=ns[x].son[0];ns[x].son[1];x=ns[x].son[1]); splay(x);return x; } int succ(int x) { splay(x); for(x=ns[x].son[1];ns[x].son[0];x=ns[x].son[0]); splay(x);return x; } int ins(int x,int s) { //cout<<"asdasda\n"; int p=pred(s); splay(p),splay(s,p); x=ns[s].son[0]=NewNode(x,s); Updata(s),Updata(p); splay(x);return x; } int kth(int k) { int x=ns[0].son[0],ls; while(true) { ls=ns[ns[x].son[0]].size; if(ls+1==k) {splay(x);return x;} if(ls < k) x=ns[x].son[1],k-=ls+1; else x=ns[x].son[0]; } } int F(int x) { splay(x);x=ns[x].son[1]; if(!ns[x].p) return 0; while(true) { if(ns[ns[x].son[0]].p) x=ns[x].son[0]; else if(ns[x].key > 0) {splay(x);return x;} else x=ns[x].son[1]; } } void rot(int x) { int ST=Stype(x),f=ns[x].f; ns[ns[f].f].son[Stype(f)]=x; ns[x].f=ns[f].f; ns[f].son[ST]=ns[x].son[!ST]; if(ns[x].son[!ST]) ns[ns[x].son[!ST]].f=f; ns[f].f=x; ns[x].son[!ST]=f; Updata(f); } void splay(int x,int to=0) { while(ns[x].f!=to) if(ns[ns[x].f].f!=to) { if(Stype(x)==Stype(ns[x].f)) rot(ns[x].f),rot(x); else rot(x),rot(x); } else rot(x); Updata(x); } void Del(int x) { int s=succ(x),p=pred(x); splay(p),splay(s,p); ns[s].son[0]=0; Updata(s),Updata(p); } ll S(int l,int r) { splay(l),splay(r,l); return ns[ns[r].son[0]].sum; } }T; void run() { priority_queue< int, vector<int>, greater<int> > H; for(int i=1;i<=m;i++) H.push(i); T.init(); char ch[8];int x,w,w2,key; for(int i=1;i<=m;i++) { scanf("%s%d",ch,&x); if(ch[0]=='i') { key=H.top();H.pop(); posp[key]=w=T.ins(key,T.kth(x+2)); w2=T.F(w); if(w2) posn[key]=T.ins(-key,posn[T[w2]]); else posn[key]=T.ins(-key,T.end); } else if(ch[0]=='r') { T.Del(posn[x]); T.Del(posp[x]); H.push(x); } else printf("%I64d\n", T.S(posp[x], posn[x])); } } int main() { int t=0; while(~scanf("%d",&m)) { printf("Case #%d:\n", ++t); run(); } return 0; }
hdu3487--区间翻转,切割
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN = 333333; #define m_set(ptr,v,type,size) memset(ptr,v,sizeof(type)*size) #define loop(begin,end) for(int i=begin;i<end;i++) class SplayTree{ #define l(x) (nod[x].son[0]) #define r(x) (nod[x].son[1]) #define Juge(x) (nod[pre[x]].son[1]==x) #define mid(x,y) ((x+y)>>1) public: int a[MAXN],pre[MAXN]; struct node{int val,rev,sz,son[2];}nod[MAXN]; int root,tot; void init(){ memset(nod,0,sizeof(nod)); root = tot = 0; } void read(int n){ a[1] = a[n+2] = 0; loop(2,n+2){ a[i] = i-1; } } void push_up(int rt){ nod[rt].sz=nod[l(rt)].sz+nod[r(rt)].sz+1; } void swap(int &x,int &y){ int tmp = x; x = y; y = tmp; } void push_down(int rt){ if(nod[rt].rev){ swap(l(rt),r(rt)); if(l(rt)) nod[l(rt)].rev ^= 1;//采用异或 ^= if(r(rt)) nod[r(rt)].rev ^= 1; nod[rt].rev = 0; } } void rotate(int x,int f){ /**分三步旋转**/ /**第一步:把x和y的儿子连好**/ int y = pre[x]; nod[y].son[!f]=nod[x].son[f]; if(nod[y].son[!f]) pre[nod[y].son[!f]] = y; push_up(y); /**第二步:把x的父亲连好**/ if(pre[y]) nod[pre[y]].son[r(pre[y])==y]=x; pre[x] = pre[y]; /**第三步:把y的父亲连好**/ nod[x].son[f] = y; pre[y] = x; } void splay(int x,int goal) { /**分三种情形的旋转!**/ while(pre[x]!=goal) { int y = pre[x], z = pre[pre[x]]; if(z==goal) { rotate(x,!Juge(x)); } else { if(Juge(y)) { if(Juge(x)) rotate(y,0),rotate(x,0); else rotate(x,1),rotate(x,0); } else { if(!Juge(x)) rotate(y,1),rotate(x,1); else rotate(x,0),rotate(x,1); } } } push_up(x);/**最后在更新x的信息,没必要在rotate里面去更新,它里面只需更新改动的父亲结点信息!**/ if(goal==0) root = x;/**要记得维护一下 root的信息!**/ } void rotateTo(int k,int goal){ /**先找到第k个位置,然后splay到goal!**/ int x = root; while(1){ push_down(x); int tmp = nod[l(x)].sz+1; if(k==tmp) break; else if(k<tmp) x = l(x); else{ k -= tmp; x = r(x); } } splay(x,goal); } void buildTree(int l,int r,int &rt,int f){ /**二分的去建树!**/ if(l>r)return; int m = mid(l,r); rt = ++tot; nod[rt].val=a[m]; pre[rt] = f; buildTree(l,m-1,l(rt),rt); buildTree(m+1,r,r(rt),rt); push_up(rt);/**返回的时候,将根结点信息更新!**/ } void rangeCut(int l,int r,int goal){ /**先删除一段**/ rotateTo(l-1,0); rotateTo(r+1,root); int x = l(r(root)); l(r(root)) = 0; pre[x] = 0; push_up(r(root)); push_up(root); /**后插入一段**/ rotateTo(goal,0); rotateTo(goal+1,root); l(r(root)) = x; pre[x] = r(root); push_up(r(root)); push_up(root); } void rangeFlip(int l,int r){ rotateTo(l-1,0); rotateTo(r+1,root); int x = l(r(root)); nod[x].rev^=1;/**延迟标记**/ } void dfs(int rt,int &size){ if(!rt) return; push_down(rt);/**遍历使要下放延迟标记,才能得到正确结果!**/ dfs(l(rt),size); a[size++] = nod[rt].val; dfs(r(rt),size); } /////////////////debug/////////////////////// }spt; int main(){ int n,m; while(scanf("%d%d",&n,&m),!(n<0&&m<0)){ spt.init(); spt.read(n); spt.buildTree(1,n+2,spt.root,0); char op[5]; int a,b,c; while(m--){ scanf("%s%d%d",op,&a,&b); if(op[0]=='C'){ scanf("%d",&c); spt.rangeCut(a+1,b+1,c+1); }else{ spt.rangeFlip(a+1,b+1); } } n = 0; spt.dfs(spt.root,n); loop(1,n-1){ if(i!=1)printf(" "); printf("%d",spt.a[i]); } printf("\n"); } return 0; }
hdu4286--双向链表实现的区间翻转\
TLE 普通的翻转,即每翻转一次就把区间里所有节点都翻转过来!
#include <iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 500010 struct Node { int pred,last,vol; }a[maxn]; int l,r,tot,size; void reverse() { for(int i=a[l].last;i!=r;i=a[i].pred) swap(a[i].pred,a[i].last); a[a[l].last].last=r; a[a[r].pred].pred=l; swap(a[l].last,a[r].pred); } void Del(char ch) { size--; if(ch=='L') { a[a[a[l].last].last].pred=l; a[l].last=a[a[l].last].last; } else { a[a[a[r].pred].pred].last=r; a[r].pred=a[a[r].pred].pred; } } void init(int n) { tot=0;size=0; l=0;r=n+1; a[l].pred=-1;a[l].last=r; a[r].pred=l;a[r].last=-1; } void Insert(char ch,int vol) { a[++tot].vol=vol;size++; if(ch=='L') { a[tot].pred=l; a[tot].last=a[l].last; a[a[l].last].pred=tot; a[l].last=tot; } else { a[tot].last=r; a[tot].pred=a[r].pred; a[a[r].pred].last=tot; a[r].pred=tot; } } void left(char ch) { if(ch=='L') l=a[l].pred; else r=a[r].pred; } void right(char ch) { if(ch=='L') l=a[l].last; else r=a[r].last; } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); init(n); for(int i=1;i<=n;i++) { scanf("%d",&a[++tot].vol); a[tot].pred=l; a[tot].last=a[l].last; a[l].last=tot; a[a[tot].last].pred=tot; l=tot;size++; } scanf("%d%d",&l,&r);l--;r++; int m; scanf("%d",&m); while(m--) { char op[10]; scanf("%s",op); if(op[0]=='R') {reverse(); continue;} else if(op[0]=='D') {scanf(" %c",&op[0]);Del(op[0]);} else if(op[0]=='I') {int d;scanf(" %c%d",&op[0],&d);Insert(op[0],d);} else { char ch; scanf(" %c",&ch); if(strcmp(op,"MoveLeft")==0) left(ch); else right(ch); } } for(int i=1,k=0;i<=size;i++) { k=a[k].last; if(i==1) printf("%d",a[k].vol); else printf(" %d",a[k].vol); } printf("\n"); } return 0; }
只要 在L 的前面设一个 LL 在R后面设一个 RR就可以避免上述的没翻转一次全部结点翻转了!
这样的话,LL就相当于是给 L 一个方向感! RR也是一样的,只不过它代表R的后.
/* HDU G++ 4015ms 11968K 双向链表模拟 注意细节 */ #include<stdio.h> #include<string.h> #include<algorithm> #include<algorithm> using namespace std; const int MAXN=2000000; struct Node { int from; int to; int val; }node[MAXN]; int tol; int L,R;//两个指针 int LL,RR;//分别是指针L,R的左侧和右侧,由于倒一下可能改变方向,所以记录下方向 int n; void moveleft_L(void)//左移L指针 { if(L==0)return;//最左侧了 if(node[L].to==LL) { LL=L; L=node[L].from; } else { LL=L; L=node[L].to; } } void moveleft_R() { if(RR==0)return; if(node[RR].to==R) { R=RR; RR=node[RR].from; } else { R=RR; RR=node[RR].to; } } void moveright_L() { if(LL==n+1)return; if(L==node[LL].from) { L=LL; LL=node[LL].to; } else { L=LL; LL=node[LL].from; } } void moveright_R() { if(R==n+1)return; if(node[R].from==RR) { RR=R; R=node[R].to; } else { RR=R; R=node[R].from; } } void insert_L(int v) { node[tol].val=v; node[tol].from=L; node[tol].to=LL; if(node[L].to==LL)node[L].to=tol; else node[L].from=tol; if(node[LL].from==L)node[LL].from=tol; else node[LL].to=tol; LL=tol; tol++; } void insert_R(int v) { node[tol].val=v; node[tol].from=RR; node[tol].to=R; if(node[RR].to==R)node[RR].to=tol; else node[RR].from=tol; if(node[R].from==RR)node[R].from=tol; else node[R].to=tol; RR=tol; tol++; } void del_L() { if(LL==n+1)return; if(L==n+1)return; int t; if(node[LL].from==L)t=node[LL].to; else t=node[LL].from; if(node[t].from==LL)node[t].from=L; else node[t].to=L; if(node[L].to==LL)node[L].to=t; else node[L].from=t; LL=t; } void del_R() { if(RR==0)return; if(R==0)return; int t; if(node[RR].to==R)t=node[RR].from; else t=node[RR].to; if(node[t].from==RR)node[t].from=R; else node[t].to=R; if(node[R].from==RR)node[R].from=t; else node[R].to=t; RR=t; } void reverse() { if(node[L].to==LL)node[L].to=RR; else node[L].from=RR; if(node[LL].from==L)node[LL].from=R; else node[LL].to=R; if(node[R].from==RR)node[R].from=LL; else node[R].to=LL; if(node[RR].to==R)node[RR].to=L; else node[RR].from=L; int temp; temp=LL; LL=RR; RR=temp; } void output() { int flag=true; int tt=0; for(int i=node[0].to;i!=n+1;) { if(flag)flag=false; else printf(" "); printf("%d",node[i].val); if(node[i].from==tt) { tt=i; i=node[i].to; } else { tt=i; i=node[i].from; } } printf("\n"); } char str[20]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; int m; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&node[i].val); node[i].from=i-1; node[i].to=i+1; } node[0].to=1; node[0].from=-1; node[n+1].from=n; node[n+1].to=-1; tol=n+2;//结点数 scanf("%d%d",&LL,&RR); L=LL-1; R=RR+1; scanf("%d",&m); while(m--) { scanf("%s",&str); if(strcmp(str,"MoveLeft")==0) { scanf("%s",&str); if(str[0]=='L')moveleft_L(); else moveleft_R(); } else if(strcmp(str,"MoveRight")==0) { scanf("%s",&str); if(str[0]=='L')moveright_L(); else moveright_R(); } else if(strcmp(str,"Delete")==0) { scanf("%s",&str); if(str[0]=='L')del_L(); else del_R(); } else if(strcmp(str,"Insert")==0) { scanf("%s",&str); if(str[0]=='L') { int v; scanf("%d",&v); insert_L(v); } else { int v; scanf("%d",&v); insert_R(v); } } else reverse(); } output(); } }