UVa 11922 & splay的合并与分裂
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa 11922 & splay的合并与分裂相关的知识,希望对你有一定的参考价值。
题意:
1个1—n的排列,实现一下操作:将a—b翻转并移动至序列的最后。
SOL:
splay维护区间的裸题——不过平衡树的题目貌似都是裸的吧...就是看操作的复杂程度罢...
如何取区间呢,我们在splay中新增两个头尾结点,我们暂且把他叫做卫兵好了,永远把序列夹在中间——注意这个永远,我们在进行序列操作时便要维护并利用这个永远。
取序列在那个splay的线段树中已经讲过了,我们分离出一棵子树即可,如何插入呢。我们注意到要将这个点插入序列尾,它一定在尾卫兵与分离后序列最末结点之间。那么我们只要将前者旋到根,它的右子树一定只有尾卫兵。那么我们只要将分离出来的子树合并到尾卫兵,作为尾卫兵的左孩子即可。
至于翻转,打个标记交换子树——多么方便的事情。
代码其实也不是很长,头文件占了一半的长度,速度...——我很好奇为什么在vjudge里这道题加不加入读优化速度居然差不多。。260ms不算优秀,也在中游水平了吧。。并不知道还有什么细节没有实现好——我觉得pushdown的选择大概还是有些冗余。边学边优化吧。
与老人家的代码的比较:
空间为什么是0我非常不解,时间上被碾压啊...因为老人家的splay用指针搞只能自顶向下,然后他能边找kth边转,貌似就少了一半时间...要么还是我打丑了...
CODE:
/*========================================================================== # Last modified: 2016-02-20 14:43 # Filename: 11922.cpp # Description: ==========================================================================*/ #define me AcrossTheSky #include <cstdio> #include <cmath> #include <ctime> #include <string> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <set> #include <map> #include <stack> #include <queue> #include <vector> #define lowbit(x) (x)&(-x) #define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++) #define FORP(i,a,b) for(int i=(a);i<=(b);i++) #define FORM(i,a,b) for(int i=(a);i>=(b);i--) #define ls(a,b) (((a)+(b)) << 1) #define rs(a,b) (((a)+(b)) >> 1) #define getlc(a) ch[(a)][0] #define getrc(a) ch[(a)][1] #define maxn 200000 #define maxm 100000 #define pi 3.1415926535898 #define _e 2.718281828459 #define INF 1070000000 using namespace std; typedef long long ll; typedef unsigned long long ull; template<class T> inline void read(T& num) { bool start=false,neg=false; char c; num=0; while((c=getchar())!=EOF) { if(c==‘-‘) start=neg=true; else if(c>=‘0‘ && c<=‘9‘) { start=true; num=num*10+c-‘0‘; } else if(start) break; } if(neg) num=-num; } /*==================split line==================*/ int n,m; int v[maxn],s[maxn],ch[maxn][2],fa[maxn],flip[maxn]; int cnt=0,root,null; void updata(int node){s[node]=s[getlc(node)]+s[getrc(node)]+1;} int build(int sz){ if (sz<=0) return 0; int t=build(sz/2),node=++cnt; fa[ch[node][0]=t]=node; t=build(sz-sz/2-1); fa[ch[node][1]=t]=node; v[node]=node-1; updata(node); return node; } void pushdown(int x){ if (!flip[x]) return; flip[x]=0; flip[getlc(x)]^=1; flip[getrc(x)]^=1; swap(ch[x][0],ch[x][1]); } void rotate(int x){ int p=fa[x],q=fa[p],d=ch[p][1]==x; pushdown(x); fa[ch[p][d]=ch[x][d^1]]=p; updata(p); fa[ch[x][d^1]=p]=x; updata(x); fa[x]=q; if (q){ if (ch[q][0]==p) ch[q][0]=x; else if(ch[q][1]==p) ch[q][1]=x; } } void splay(int x,int &aim){ for(int y;(y=fa[x])!=aim;rotate(x)) if (fa[y]!=aim) rotate((getlc(y)==x)==(getrc(fa[y])==y)?y:x); if (aim==0) root=x; updata(x); } int kth(int node,int k){ int x=node; while (x){ pushdown(x); int ss=0; if (ch[x][0]!=0) ss=s[ch[x][0]]; if (k==ss+1) return x; if (k<=ss) x=ch[x][0]; else if (k>ss+1) x=ch[x][1],k-=ss,k--; } } void change(int l,int r){ int node=kth(root,l); splay(node,null); node=kth(getrc(root),r-l+2); splay(node,root); int t=getlc(getrc(root)); flip[t]^=1; getlc(getrc(root))=0; updata(getrc(root)); updata(root); int k=s[root]-2; node=kth(root,k+1); splay(node,null); node=kth(getrc(root),1); splay(node,root); fa[t]=getrc(root); getlc(getrc(root))=t; updata(getrc(root)); updata(root); } void print(int node){ if (node==0) return; pushdown(node); print(ch[node][0]); if (node!=1 && node!=n+2) printf("%d\n",node-1); print(ch[node][1]); } int main(){ read(n); read(m); memset(flip,0,sizeof(flip)); root=build(n+2); FORP(i,1,m){ int x,y; read(x); read(y); change(x,y); } print(root); }
以上是关于UVa 11922 & splay的合并与分裂的主要内容,如果未能解决你的问题,请参考以下文章
UVA 11922 Permutation Transformer —— splay伸展树
Uva 11922 Permutation Transformer