3223: Tyvj 1729 文艺平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 4854 Solved: 2844
[ Submit][ Status][ Discuss]
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
每次翻转操作[l, r]直接将节点l-1翻转到根,将节点r+1翻转到根的右孩子
这样r+1的左子树就是要翻转的区间了!
将该子树中所有节点的两个儿子交换位置就好了
直接暴力可能会超时,打延迟标记即可
splay参考http://blog.csdn.net/jaihk662/article/details/75213675
#include<stdio.h>
#include<algorithm>
using namespace std;
int n, m, root;
int fa[100077], tre[100077][2], v[100077];
int siz[100077];
bool rev[100077];
void Update(int k)
{
siz[k] = siz[tre[k][0]]+siz[tre[k][1]]+1;
}
void Create(int l, int r, int last)
{
int mid;
if(l>r)
return;
mid = (l+r)/2;
if(l==r)
{
siz[mid] = 1;
fa[mid] = last;
if(mid<last) tre[last][0] = mid;
else tre[last][1] = mid;
return;
}
Create(l, mid-1, mid);
Create(mid+1, r, mid);
fa[mid] = last;
Update(mid);
if(mid<last) tre[last][0] = mid;
else tre[last][1] = mid;
}
void Lazy(int k)
{
if(rev[k])
{
swap(tre[k][0], tre[k][1]);
rev[tre[k][0]] ^= 1;
rev[tre[k][1]] ^= 1;
rev[k] = 0;
}
}
void Rotate(int x, int &k)
{
int l, r, y, z;
y = fa[x], z = fa[y];
if(tre[y][0]==x) l = 0;
else l = 1;
r = l^1;
if(y==k)
k = x;
else
{
if(tre[z][0]==y) tre[z][0] = x;
else tre[z][1] = x;
}
fa[x] = z, fa[y] = x;
fa[tre[x][r]] = y;
tre[y][l] = tre[x][r];
tre[x][r] = y;
Update(y);
Update(x);
}
void Splay(int x, int &k)
{
int y, z;
while(x!=k)
{
y = fa[x], z = fa[y];
if(y!=k)
{
if((tre[y][0]==x)^(tre[z][0]==y))
Rotate(x, k);
else
Rotate(y, k);
}
Rotate(x, k);
}
}
int Find(int k, int rank)
{
int l, r;
Lazy(k);
l = tre[k][0], r = tre[k][1];
if(siz[l]+1==rank)
return k;
else if(siz[l]>=rank)
return Find(l, rank);
else
return Find(r, rank-siz[l]-1);
}
void Turn(int l, int r)
{
int x, y, z;
x = Find(root, l-1);
y = Find(root, r+1);
Splay(x, root);
Splay(y, tre[x][1]);
z = tre[y][0];
rev[z] ^= 1;
}
int main(void)
{
int i, l, r;
scanf("%d%d", &n, &m);
for(i=1;i<=n+2;i++)
v[i] = i;
Create(1, n+2, 0);
root = (n+3)/2;
for(i=1;i<=m;i++)
{
scanf("%d%d", &l, &r);
Turn(l+1, r+1);
}
for(i=2;i<=n+1;i++)
printf("%d ", Find(root, i)-1);
printf("\n");
return 0;
}