[luogu P3391] 文艺平衡树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu P3391] 文艺平衡树相关的知识,希望对你有一定的参考价值。
[luogu P3391] 文艺平衡树
题目背景
这是一道经典的Splay模板题——文艺平衡树。
题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
输入输出格式
输入格式:
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, \cdots n-1,n)(1,2,?n−1,n) m表示翻转操作次数
接下来m行每行两个数 [l,r][l,r] 数据保证 1 \leq l \leq r \leq n1≤l≤r≤n
输出格式:
输出一行n个数字,表示原始序列经过m次变换后的结果。
输入输出样例
说明
n,m≤100000
上次就很想写了,splay的妙用。
splay能做到一般的平衡树做不到的东西——维护序列。
为什么一般的平衡树做不到?正是因为splaytree的核心操作——splay。
这个log级别的操作能将一个连续的子序列搞到一棵子树中。
比如要维护[l,r],则调用一下splay(find(l-1),0),splay(find(r+1),root)。
但是要注意一下,对于这题,我们需要一个节点在当前序列的排名和初始位置(即权值)。
一个节点的排名是它的左子树大小+1,初始位置是不变的。
对于这题,还有一个巧妙的地方,就是reverse操作。
这里用到了和线段树类似的lazy打标记,延迟下传的思想。还是很厉害的。
输出的话,根据二叉搜索树的性质,直接中序遍历。
code:
View Code1 #include <cstdio> 2 #include <iostream> 3 4 void OJ_file() { 5 #ifndef ONLINE_JUDGE 6 freopen("in.txt","r",stdin); 7 freopen("out.txt","w",stdout); 8 #endif 9 } 10 namespace fastIO { 11 #define puc(c) putchar(c) 12 inline int read() { 13 int x=0,f=1; char ch=getchar(); 14 while (ch<‘0‘||ch>‘9‘) { 15 if (ch==‘-‘) f=-f; 16 ch=getchar(); 17 } 18 while (ch>=‘0‘&&ch<=‘9‘) { 19 x=(x<<3)+(x<<1)+ch-‘0‘; 20 ch=getchar(); 21 } 22 return x*f; 23 } 24 int cnt,w[20]; 25 template <class T> inline void write(T x) { 26 if (x==0) { 27 puc(‘0‘); return; 28 } 29 if (x<0) x=-x,puc(‘-‘); 30 for (cnt=0; x; x/=10) w[++cnt]=x%10; 31 for (; cnt; --cnt) puc(w[cnt]+48); 32 } 33 inline void newblank() { 34 puc(‘ ‘); 35 } 36 } using namespace fastIO; 37 38 int n,m; 39 #define SplayTree node 40 struct SplayTree { 41 int v,k; bool r; 42 node* c[3]; 43 node () { 44 v=k=r=0; 45 c[0]=c[1]=c[2]=0; 46 } 47 }*ro; 48 void newnode (node* &x,int k) { 49 x=new node(),x->v=1,x->k=k; 50 } 51 void refresh (node* x) { 52 x->v=1; 53 if (x->c[0]) x->v+=x->c[0]->v; 54 if (x->c[1]) x->v+=x->c[1]->v; 55 } 56 void transfer (node* x) { 57 if (x->r) { 58 if (x->c[0]) x->c[0]->r^=1; 59 if (x->c[1]) x->c[1]->r^=1; 60 x->r=0,std::swap(x->c[0],x->c[1]); 61 } 62 } 63 #define M ((l)+(r)>>1) 64 void setup (node* &x,int l,int r) { 65 if (l>r) return; 66 newnode(x,M); 67 setup(x->c[0],l,M-1),setup(x->c[1],M+1,r); 68 if (x->c[0]) x->c[0]->c[2]=x; 69 if (x->c[1]) x->c[1]->c[2]=x; 70 refresh(x); 71 } 72 bool dir (node* x) { 73 if (!x->c[2]) return 0; 74 return x->c[2]->c[1]==x; 75 } 76 void linknode (node* y,node* x,bool p) { 77 if (x) x->c[2]=y; 78 if (y) y->c[p]=x; 79 } 80 void rotate (node* x) { 81 bool p=dir(x); node* y=x->c[2]; 82 linknode(y->c[2],x,dir(y)); 83 linknode(y,x->c[p^1],p); 84 linknode(x,y,p^1); 85 refresh(y),refresh(x); 86 } 87 void splay (node* x,node* an) { 88 if (x->c[2]==an) return; 89 while (x->c[2]!=an) { 90 if (x->c[2]->c[2]==an) { 91 rotate(x); 92 if (!an) ro=x; 93 return; 94 } 95 rotate(dir(x)^dir(x->c[2])?x:x->c[2]); 96 rotate(x); 97 } 98 if (!an) ro=x; 99 } 100 node* find (node* x,int v) { 101 transfer(x); 102 int s=x->c[0]?x->c[0]->v:0; 103 if (v==s) return x; 104 if (v<s+1) return find(x->c[0],v); 105 else return find(x->c[1],v-s-1); 106 } 107 void reverse (int l,int r) { 108 node* q[2]={find(ro,l-1),find(ro,r+1)}; 109 splay(q[0],0),splay(q[1],ro); 110 ro->c[1]->c[0]->r^=1; 111 } 112 void dfs (node* x) { 113 transfer(x); 114 if (x->c[0]) dfs(x->c[0]); 115 if (x->k>=1&&x->k<=n) { 116 write(x->k),newblank(); 117 } 118 if (x->c[1]) dfs(x->c[1]); 119 } 120 int main() { 121 OJ_file(); 122 n=read(),m=read(),ro=0; 123 setup(ro,0,n+1); 124 int l,r; 125 for (; m; --m) { 126 l=read(),r=read(); 127 if (l==r) continue; 128 reverse(l,r); 129 } 130 dfs(ro); 131 return 0; 132 }
以上是关于[luogu P3391] 文艺平衡树的主要内容,如果未能解决你的问题,请参考以下文章