BZOJ 3223 文艺平衡树
题目描述 Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
最开始所有元素都是0。
输入描述 Input Description
第一行为n,m
n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)
m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1≤l≤r≤n
输出描述 Output Description
输出一行n个数字,表示原始序列经过m次变换后的结果
样例输入 Sample Input
5 3
1 3
1 3
1 4
样例输出 Sample Output
4 3 2 1 5
数据范围及提示 Data Size & Hint
n,m≤100000
分析:
这个题目要求我们进行旋转操作,怎么办呢?
模拟肯定超时~放弃
题目不是给了你提示么–平衡树
那么我们用Splay来维护这个序列
因为Splay满足二叉搜索树的性质,那么如果把每个点的左右儿子交换,那么这些点的中序遍历就翻转了
于是将l-1和r+1号节点分别提至根节点和根节点的右儿子,那么要操作的序列就是r+1号节点的左儿子,直接给它打上一个翻转标记,等到下次遇到这个点是就下传标记并且翻转左右子树即可(像不像线段树lazy_tag?)
Code:
#include <bits/stdc++.h>
using namespace std;
#define inf 2100000000
#define maxn 100010
int ch[maxn][2],f[maxn],size[maxn],key[maxn],lazy[maxn];
int sz,root;
int read() {
int ans=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
return ans*flag;
}
bool get(int x) {return ch[f[x]][1]==x;}
void update(int x) {
if(x) {
size[x]=1;
if(ch[x][0]) size[x]+=size[ch[x][0]];
if(ch[x][1]) size[x]+=size[ch[x][1]];
}
return ;
}
void pushdown(int x) { //push down lazy tag
if(x && lazy[x]) {
lazy[ch[x][0]]^=1;
lazy[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
lazy[x]=0;
}
return ;
}
void rotate(int x) {
int old=f[x],oldf=f[old],whichx=get(x);
pushdown(old);
pushdown(x);
ch[old][whichx]=ch[x][whichx^1];
f[ch[old][whichx]]=old;
ch[x][whichx^1]=old;
f[old]=x;
f[x]=oldf;
if(oldf)
ch[oldf][ch[oldf][1]==old]=x;
update(old);
update(x);
return ;
}
void splay(int x,int tar) { //rotate x to tar
for(int fa;(fa=f[x])!=tar;rotate(x))
if(f[fa]!=tar)
rotate(get(x)==get(fa)?fa:x);
if(!tar)
root=x;
return ;
}
int findx(int x) { //by search the ranking return the treenumber
int now=root;
while(1) {
pushdown(now);
if(ch[now][0]&&x<=size[ch[now][0]])
now=ch[now][0];
else {
int tmp=(ch[now][0]?size[ch[now][0]]:0)+1;
if(x<=tmp) return now;
x-=tmp;
now=ch[now][1];
}
}
}
void insert(int x) {
if(root==0) {
sz++;
ch[sz][0]=ch[sz][1]=f[sz]=0;
root=sz;
size[sz]=1;
key[sz]=x;
return ;
}
int now=root,fa=0;
while(1) {
if(x==key[now]) {
update(now);
update(fa);
splay(now,0);
break;
}
fa=now;
now=ch[now][key[now]<x];
if(now==0) {
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;
size[sz]=1;
ch[fa][key[fa]<x]=sz;
key[sz]=x;
update(fa);
splay(sz,0);
break;
}
}
return ;
}
void print(int x) {
pushdown(x);
if(ch[x][0])
print(ch[x][0]);
if(key[x]!=inf && key[x]!=-inf)
printf("%d ",key[x]);
if(ch[x][1])
print(ch[x][1]);
return ;
}
int main() {
int n,m,l,r;
n=read(),m=read();
insert(-inf);
for(int i=1;i<=n;i++)
insert(i);
insert(inf);
for(int i=1;i<=m;i++) {
l=read(),r=read();
l=findx(l);
r=findx(r+2);
splay(l,0);
splay(r,l);
lazy[ch[ch[root][1]][0]]^=1;
}
print(root);
return 0;
}