[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,?n1,n) m表示翻转操作次数

接下来m行每行两个数 [l,r][l,r] 数据保证 1 \leq l \leq r \leq n1lrn

输出格式:

输出一行n个数字,表示原始序列经过m次变换后的结果。

输入输出样例

输入样例#1: 复制
5 3
1 3
1 3
1 4
输出样例#1: 复制
4 3 2 1 5

说明

n,m100000

上次就很想写了,splay的妙用。

splay能做到一般的平衡树做不到的东西——维护序列。

为什么一般的平衡树做不到?正是因为splaytree的核心操作——splay。

这个log级别的操作能将一个连续的子序列搞到一棵子树中。

比如要维护[l,r],则调用一下splay(find(l-1),0),splay(find(r+1),root)。

但是要注意一下,对于这题,我们需要一个节点在当前序列的排名和初始位置(即权值)。

一个节点的排名是它的左子树大小+1,初始位置是不变的。

对于这题,还有一个巧妙的地方,就是reverse操作。

这里用到了和线段树类似的lazy打标记,延迟下传的思想。还是很厉害的。

输出的话,根据二叉搜索树的性质,直接中序遍历。

code:

技术分享图片
  1 #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 }
View Code

 

以上是关于[luogu P3391] 文艺平衡树的主要内容,如果未能解决你的问题,请参考以下文章

[Splay]luogu P3391 文艺平衡树

P3391 模板文艺平衡树(Splay)

P3391 模板文艺平衡树(Splay)新板子

AC日记——文艺平衡树 洛谷 P3391

P3391 模板文艺平衡树(Splay)

洛谷P3391 模板文艺平衡树(Splay)