[BZOJ3223]Tyvj 1729 文艺平衡树
Tyvj 1729 文艺平衡树
题面
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
Input
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n
Output
输出一行n个数字,表示原始序列经过m次变换后的结果
Sample Input
5 3
1 3
1 3
1 4
Sample Output
4 3 2 1 5
HINT
N,M<=100000
思路
模板splay(不带区间操作)是按照权值来排序维护二叉查找树的。如果把splay推广到区间操作,我们需要进行一些修改。把一个元素在区间中的下标(即第几个)作为splay树的权值。所以对于这棵splay树的根节点,左边的所有节点在序列中的位置都在根节点之前。这样如果我们需要操作区间\([l,r]\),我们就先把l-1转到root,再把r+1转到root的右儿子,那么root的右儿子的左子树则是区间\([l,r]\)对应的所有节点。splay树中排名为k的节点则是序列中第k个节点。
我们可以发现,对于一个子树,子树的根节点的左子树就是在根节点左侧的点,右子树就是在根节点右侧的点。那么我们容易发现,如果把左右子树换一下,然后递归的更新左右子树即可。
为了优化时间,我们可以像线段树一样打个tag来维护翻转操作。同时Push_Down操作就是下传tag同时交换左右子树。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define maxn (int)(1e5+1000)
#define inf (int)(1e9+1000)
using namespace std;
int
val[maxn],tag[maxn],size[maxn],son[maxn][2],fa[maxn],cnt[maxn],s[maxn];
int n,m,idx,root;
void push_down(int x){
if(!tag[x])return;
if(son[x][0]){
tag[son[x][0]]^=1;
}
if(son[x][1]){
tag[son[x][1]]^=1;
}
tag[x]=0;
swap(son[x][0],son[x][1]);
return;
}
void push_up(int x){
size[x]=cnt[x];
if(son[x][0]){
size[x]+=size[son[x][0]];
}
if(son[x][1]){
size[x]+=size[son[x][1]];
}
return;
}
void Down(int x){
if(!x)return;
Down(fa[x]);
push_down(x);
return;
}
void rotate(int x){
int y=fa[x],z=fa[y],o=(son[y][1]==x);
son[y][o]=son[x][o^1];
fa[son[x][o^1]]=y;
son[x][o^1]=y;
fa[y]=x;
son[z][son[z][1]==y]=x;
fa[x]=z;
push_up(y);
push_up(x);
return;
}
void splay(int x,int v=0){
Down(x);
for(int y;fa[x]!=v&&fa[x];rotate(x)){
y=fa[x];
if(fa[y]==v)continue;
rotate((son[fa[x]][0]==x)^(son[fa[y]][0]==y)?x:y);
}
if(!v)root=x;
}
void insert(int x,int a){
int y=0;
while(x&&val[x]!=a){
y=x;
x=son[x][val[x]<a];
}
if(x){
cnt[x]++;push_up(x);
}
else{
x=++idx;
val[x]=a;
tag[x]=son[x][0]=son[x][1]=0;
cnt[x]=size[x]=1;
son[y][val[y]<a]=x;
fa[x]=y;
}
splay(x);
return;
}
int kth(int x,int a){
push_down(x);
if(size[son[x][0]]>=a){
return kth(son[x][0],a);
}
if(size[son[x][0]]+cnt[x]>=a){
splay(x);
return x;
}
return kth(son[x][1],a-cnt[x]-size[son[x][0]]);
}
void write(int x){
if(!x)return;
push_down(x);
write(son[x][0]);
if(-1e9<=val[x]&&val[x]<=1e9)printf("%d ",val[x]);
write(son[x][1]);
return;
}
int main(){
// freopen("in","r",stdin);
scanf("%d%d",&n,&m);
insert(root,inf);insert(root,-inf);
for(int i=1;i<=n;i++){insert(root,i);}
for(int i=1;i<=m;i++){
int l,r;scanf("%d%d",&l,&r);
l=kth(root,l+1-1);r=kth(root,r+1+1);
splay(l);splay(r,root);
tag[son[son[root][1]][0]]^=1;
push_down(son[son[root][1]][0]);
}
write(root);
return 0;
}