数据结构日常RE。
多自己带数据测就是王道吧。
解题思路:
一开始不会嘛,只好想办法套大白书上给的splay,split和merge代码。但要注意的是splay函数里的那个cmp和前面treap里的cmp不一样。splay的是比序号(也就是第几个的意思),treap的是比大小(BST的查找嘛)。所以要自己重写。然后想该怎么套咧?题目要求复制后逆序粘贴到后面,那么显然树上的节点不能同时保存值与序号(不能把值和它的位置一起记录在一个节点里),否则merge的时候就得一个节点一个节点的去维护,那就跟纯暴力算法没区别啦。所以想只能维护值或序号中的某一个。那该维护哪一个咧?我们发现伸展树,它是不存在什么维持平衡的要求(根本就不是一种平衡树啊,它只是一个BST啊),那么树的形态是任意的,从而也就不需要维护什么优先值啊,什么深度啊之类的东西了,随便你怎么rotate(rotate是一种可以保持BST性质的一种树的变换吧)。而在merge函数里我们发现竟然可以在简单调整后直接粘上去就OK了(代码上有一句注释:假定left的所有元素比right小。一开始自己一直很不理解,凭啥这么假定呢?显然多数情况下,这都不成立呀。事实上确实如此,如果你调用了这个merge函数,那么在绝大多数情况下,树将会失去BST的性质。但是本题只是希望你能理解伸展算法在树的分裂与合并中的应用,所以只是将伸展树中的一部分抽了出来成了一题。在这题中的伸展树是不具备BST性质的。但只需要通过伸展算法,便可完成树的分裂与合并。真正的伸展树可上网查,几乎都是把重心放在了树的调整而不是分裂与合并上。)。说明树的结构和形态自然而然地记录了序号,那么我们只需要定义一个树的遍历方法(如中序遍历),以记录序号。然后在节点上记录具体的值就好了。所以先中序遍历生成一个树,然后按要求split与merge,最后中序便遍历一下输出就好啦。
一些疑惑:
不知道为什么splay操作非要这么转,讨论得那么麻烦,直接递归转上来不行吗,如下,而且我也AC啦,详见代码2
void splay(Node* &o,int k)
{
o->push_down();
int d=o->cmp(k);
if(d==-1) return;
else if(d==0)
{
splay(o->ch[0],k);
rotate(o,1);
}
else if(d==1)
{
splay(o->ch[1],k-(o->ch[0]?o->ch[0]->s:0)-1);
rotate(o,0);
}
}
代码
#include<bits/stdc++.h>
using namespace std;
struct Node
{
Node* ch[2];
int v,s,r;
Node(int x)
{
v=x;
r=0;
s=1;
ch[0]=ch[1]=NULL;
}
int cmp(int x)
{
if(ch[0])
{
if(ch[0]->s>=x) return 0;
else if(ch[0]->s+1==x) return -1;
else return 1;
}
else
{
if(x==1) return -1;
else return 1;
}
}
void maintain()
{
if(!this) return;
s=1;
if(ch[0]) s+=ch[0]->s;
if(ch[1]) s+=ch[1]->s;
}
void push_down()
{
if(!this) return;
if(r)
{
r=0;
swap(ch[0],ch[1]);
if(ch[0]) ch[0]->r^=1;
if(ch[1]) ch[1]->r^=1;
}
}
};
void rotate(Node* &o,int d)
{
o->push_down();
Node* k=o->ch[d^1];
k->push_down();
o->ch[d^1]=k->ch[d];
k->ch[d]=o;
o->maintain();
k->maintain();
o=k;
}
void splay(Node* &o,int k)
{
o->push_down();
int d=o->cmp(k);
if(d==1) k-=(o->ch[0]?o->ch[0]->s:0)+1;
if(d!=-1)
{
Node* p=o->ch[d];
p->push_down();
int d2=p->cmp(k);
int k2=d2==0?k:k-(p->ch[0]?p->ch[0]->s:0)-1;
if(d2!=-1)
{
splay(p->ch[d2],k2);
if(d==d2) rotate(o,d^1);
else rotate(o->ch[d],d);
}
rotate(o,d^1);
}
}
Node* merge(Node* left,Node* right)
{
if(left)
{
splay(left,left->s);
left->ch[1]=right;
left->maintain();
}
else left=right;
return left;
}
void split(Node* o,int k,Node* &left,Node* &right)
{
if(!k)
{
left=NULL;
right=o;
return;
}
splay(o,k);
left=o;
right=o->ch[1];
o->ch[1]=NULL;
left->maintain();
}
Node* init(int l,int r)
{
if(l>r) return NULL;
int m=l+(r-l)/2;
Node* ret=new Node(m);
ret->ch[0]=init(l,m-1);
ret->ch[1]=init(m+1,r);
ret->maintain();
return ret;
}
void dfs(Node* o)
{
if(!o) return;
o->push_down();
dfs(o->ch[0]);
printf("%d\n",o->v);
dfs(o->ch[1]);
}
int main()
{
int n,m;
int a,b;
scanf("%d %d",&n,&m);
Node* o=init(1,n);
Node *le,*ri,*mi;
while(m--)
{
scanf("%d %d",&a,&b);
split(o,a-1,le,ri);
split(ri,b-a+1,mi,ri);
mi->r^=1;
o=merge(le,ri);
o=merge(o,mi);
}
dfs(o);
return 0;
}
代码2
#include<bits/stdc++.h>
using namespace std;
struct Node
{
Node* ch[2];
int v,s,r;
Node(int x)
{
v=x;
r=0;
s=1;
ch[0]=ch[1]=NULL;
}
int cmp(int x)
{
if(ch[0])
{
if(ch[0]->s>=x) return 0;
else if(ch[0]->s+1==x) return -1;
else return 1;
}
else
{
if(x==1) return -1;
else return 1;
}
}
void maintain()
{
if(!this) return;
s=1;
if(ch[0]) s+=ch[0]->s;
if(ch[1]) s+=ch[1]->s;
}
void push_down()
{
if(!this) return;
if(r)
{
r=0;
swap(ch[0],ch[1]);
if(ch[0]) ch[0]->r^=1;
if(ch[1]) ch[1]->r^=1;
}
}
};
void rotate(Node* &o,int d)
{
o->push_down();
Node* k=o->ch[d^1];
k->push_down();
o->ch[d^1]=k->ch[d];
k->ch[d]=o;
o->maintain();
k->maintain();
o=k;
}
void splay(Node* &o,int k)
{
o->push_down();
int d=o->cmp(k);
if(d==-1) return;
else if(d==0)
{
splay(o->ch[0],k);
rotate(o,1);
}
else if(d==1)
{
splay(o->ch[1],k-(o->ch[0]?o->ch[0]->s:0)-1);
rotate(o,0);
}
}
Node* merge(Node* left,Node* right)
{
if(left)
{
splay(left,left->s);
left->ch[1]=right;
left->maintain();
}
else left=right;
return left;
}
void split(Node* o,int k,Node* &left,Node* &right)
{
if(!k)
{
left=NULL;
right=o;
return;
}
splay(o,k);
left=o;
right=o->ch[1];
o->ch[1]=NULL;
left->maintain();
}
Node* init(int l,int r)
{
if(l>r) return NULL;
int m=l+(r-l)/2;
Node* ret=new Node(m);
ret->ch[0]=init(l,m-1);
ret->ch[1]=init(m+1,r);
ret->maintain();
return ret;
}
void dfs(Node* o)
{
if(!o) return;
o->push_down();
dfs(o->ch[0]);
printf("%d\n",o->v);
dfs(o->ch[1]);
}
int main()
{
int n,m;
int a,b;
scanf("%d %d",&n,&m);
Node* o=init(1,n);
Node *le,*ri,*mi;
while(m--)
{
scanf("%d %d",&a,&b);
split(o,a-1,le,ri);
split(ri,b-a+1,mi,ri);
mi->r^=1;
o=merge(le,ri);
o=merge(o,mi);
//dfs(o);
}
dfs(o);
return 0;
}