题意:给出初始序列a[n]=n
进行m次翻转,求最终序列。
只有在一开始,第几个点就是几号店。。。
在进行翻转后,如果还要翻转l-r,不是对l节点和r节点进行操作,而是对第l个和第r个点进行翻转。
首先,如果我们对整个序列建立平衡树,因为没有节点的增加和减少,所以整个数的结构建好了就不会改变。 即SBT的大小关系是下标,而不是值。
这样,就有了n个节点的线段树。
我们考虑怎么进行翻转,如果对整个序列进行翻转,只要把根的左右儿子互换,再把根的左儿子的左右儿子互换……交换所有的左右节点即可。那么,只要保证我们要修改的区间在平衡树的一棵子树中即可。
如何把区间变成一棵子树?设翻转l-r,只要把第l-1个节点(不是l-1号节点)splay到根,再把第r+1个节点splay到根的右儿子就行,这样以根的右儿子的左儿子为根的子树就是大于l-1,小于r+1,也就是l-r区间。
但有个问题,如果l=1或r=n呢?l-1=0,r+1>n,这就会出错,于是建树时我们把1-n的序列从2开始建到n+2,就可以避免这个问题。
至于翻转一颗子树,打lazy标记就行,pushdown的时候交换左右儿子
每次查找排名为n的点时pushdown就行
输出答案是对于每一个n,输出第n位(不是n号节点)的树就行。
要特别说说建树,直接在序列上建,如果一个一个插入太慢了,递归建树即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100010
using namespace std;
int size[N],fa[N],tr[N][3],root,v[N],tmp[N],lazy[N],n,m,i,o,p;
void pushup(int x)
{
size[x]=size[tr[x][0]]+size[tr[x][1]]+1;
}
void rotate(int x,int &rt)
{
int y=fa[x],z=fa[y],o,p;
o=(tr[y][1]==x);
p=!o;
(y==rt?rt:tr[z][tr[z][0]!=y])=x;
fa[x]=z;
fa[y]=x;
fa[tr[x][p]]=y;
tr[y][o]=tr[x][p];
tr[x][p]=y;
pushup(y);
pushup(x);
}
void splay(int x,int &rt)
{
int y,z;
while (x!=rt)
{
y=fa[x],z=fa[y];
if (y!=rt)
{
if ((tr[y][0]==x)^(tr[z][0]==y)) rotate(x,rt);
else rotate(y,rt);
}
rotate(x,rt);
}
}
void build(int father,int l,int r)
{
if (l>r) return;
int mid=(l+r)/2;
tr[father][mid>father]=mid;
size[mid]=1;
v[mid]=tmp[mid];
fa[mid]=father;
if (l==r) return;
build(mid,l,mid-1);
build(mid,mid+1,r);
pushup(mid);
}
void pushdown(int x)
{
if (!lazy[x]) return;
lazy[x]^=1;
swap(tr[x][0],tr[x][1]);
lazy[tr[x][0]]^=1;
lazy[tr[x][1]]^=1;
return;
}
int find(int x)
{
int rt=root;
while (1)
{
pushdown(rt);
if (x<=size[tr[rt][0]])
{
rt=tr[rt][0];
continue;
}
x-=size[tr[rt][0]];
if (x==1) return rt;
x--;
{
rt=tr[rt][1];
continue;
}
}
}
void rever(int x,int y)
{
x=find(x);
y=find(y);
splay(x,root);
splay(y,tr[root][1]);
lazy[tr[y][0]]^=1;
return ;
}
int main()
{
scanf("%d %d",&n,&m);
for (i=2;i<=n+1;i++)
tmp[i]=i-1;
build(0,1,n+2);
root=(n+3)/2; //(2 + n+1)/2
for (i=1;i<=m;i++)
{
scanf("%d %d",&o,&p);
rever(o,p+2);
}
for (i=2;i<=n+1;i++)
{
printf("%d ",v[find(i)]);
}
return 0;
}