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裸题。RE了几次,后来发现是建树的问题,最后改了一下建树部分就过了。
Splay的旋转方式真是不习惯呐。。。和普通的平衡树不同,不是通过引用方式修改,而是记录父节点,像链表一样修改。
自己的代码:
#include<cstdio>
#define check if(x->rev)\
{\
if(x->s[0]) seija(x->s[0]);\
if(x->s[1]) seija(x->s[1]);\
x->rev=0;\
}
using namespace std;
int n,m,l,r;
struct node
{
int v,n;
node *s[2],*fat;
bool rev;
node(int v):v(v),n(1),rev(0){s[0]=s[1]=0;}
}*rt;
void build(node* &x,int z,int y)
{
int mid=(z+y)/2;
x=new node(mid);
if(z<=mid-1) {build(x->s[0],z,mid-1);x->s[0]->fat=x;x->n+=x->s[0]->n;}
if(mid+1<=y) {build(x->s[1],mid+1,y);x->s[1]->fat=x;x->n+=x->s[1]->n;}
}
#define rlt(son,dad) (son==dad->s[0]?0:1)
#define num(x) (x?x->n:0)
#define line(a,b,c) rlt(a,b)==rlt(b,c)
inline void rot(node *son,node *dad)
{
int k=rlt(son,dad);
if(dad==rt) rt=son;
else
{
int q=rlt(dad,dad->fat);
dad->fat->s[q]=son;
}
node *x=son->s[1^k];
int b=son->n;
son->n=dad->n;dad->n+=num(x)-b;
son->fat=dad->fat;
dad->fat=son;
if(x) x->fat=dad;
dad->s[k]=x;
son->s[1^k]=dad;
}
inline void seija(node *x)
{
x->rev^=1;
node *y=x->s[0];
x->s[0]=x->s[1];
x->s[1]=y;
}
void splay(int k,node* &des)
{
node *x=rt;
int y;
while(1)
{
check;
y=x->n;
if(x->s[1]) y-=x->s[1]->n;
if(y==k) break;
if(k<y) x=x->s[0];
else
{
k-=y;
x=x->s[1];
}
}
node *z,*w;
while(x!=des)
{
z=x->fat;
if(z==des) {rot(x,z);break;}
w=z->fat;
if(line(x,z,w)) {rot(z,w);rot(x,z);}
else {rot(x,z);rot(x,w);}
if(w==des) break;
}
}
inline void seija()
{
splay(r+2,rt);
splay(l,rt->s[0]);
seija(rt->s[0]->s[1]);
}
void print(node *x)
{
check;
if(x->s[0]) print(x->s[0]);
if(x->v>=1&&x->v<=n) printf("%d ",x->v);
if(x->s[1]) print(x->s[1]);
}
int main()
{
scanf("%d%d",&n,&m);
build(rt,0,n+1);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
seija();
}
print(rt);
return 0;
}