题目:http://acm.hdu.edu.cn/showproblem.php?pid=3487
题意:给定一串序列,有两种操作:①把某段区间切到某一点后面②把某个区间颠倒
分析:这题由于涉及到区间移动,所以需要用到平衡树的旋转操作。于是新学了个splay(有个演示网站:http://www.cs.usfca.edu/~galles/visualization/SplayTree.html),学了半天还是没搞懂splay为何是平衡树。。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#define N 300050
using namespace std;
struct node
{
node *ch[2],*p;
int val,sz,rev;
void init(int _v){ch[0]=ch[1]=p=NULL;val=_v;rev=0;sz=1;};
bool d(){return p->ch[1]==this;}
void setch(int d,node *nc){ch[d]=nc;if(nc)nc->p=this;}
void updata()
{
sz = 1;
if(ch[0]) sz += ch[0]->sz;
if(ch[1]) sz += ch[1]->sz;
}
void pushdown()
{
if(rev) {
swap(ch[0], ch[1]); rev = 0;
if(ch[0]) ch[0]->rev ^= 1;
if(ch[1]) ch[1]->rev ^= 1;
}
}
}tree[N],*root,*cur;
int num,n,m;
node* maken(int v)
{
cur->init(v);
return cur++;
}
node* build(int l,int r)
{
if(l > r) return NULL;
int m = (l + r) >> 1;
node *x = maken(m);
x->setch(0, build(l, m-1));
x->setch(1, build(m+1, r));
x->updata();
return x;
}
void show(node *u){
u->pushdown();
if(u->ch[0])show(u->ch[0]);
if(num>0&&num<=n){
printf("%d",u->val);
printf("%c",num==n?'\n':' ');
}
num++;
if(u->ch[1])show(u->ch[1]);
}
node* select(int k)//找到点权为v的点
{
node *x=root;
while(true) {
x->pushdown();
int tmp = x->ch[0]?x->ch[0]->sz:0;
if(k == tmp) break;
if(k < tmp) x = x->ch[0];
else x = x->ch[1], k-=tmp+1;
}
return x;
}
void rot(node *x)
{
node *y=x->p, *z=y->p;
y->pushdown();x->pushdown();
int d=x->d();
if(z) z->setch(y->d(), x);
y->setch(d, x->ch[!d]); x->setch(!d, y); y->updata();
if(!z) root=x, x->p=NULL;
}
void splay(node *st,node *en)
{
while(st->p!=en)rot(st);st->updata();
}
void print()
{
for(int i=0;i<=n+1;i++)
{
cout<<tree[i].val<<' ';
if(tree[i].ch[0])cout<<tree[i].ch[0]->val<<' ';
if(tree[i].ch[1])cout<<tree[i].ch[1]->val;
cout<<endl;
}
}
int main()
{
while(scanf("%d%d",&n,&m)&&(n>=0||m>=0))
{
cur=tree;root=build(0,n+1);
char cmd[5];
while(m--)
{
int l,r;scanf("%s%d%d",cmd,&l,&r);
node *ln=select(l-1),*rn=select(r+1);
splay(ln,NULL);splay(rn,ln);
node *bn=rn->ch[0];
if(cmd[0]=='C'){
int pos;scanf("%d",&pos);
rn->setch(0,NULL);rn->updata();ln->updata();//把目标区间截出来
node *lpn=select(pos),*rpn=select(pos+1);
splay(lpn,NULL);splay(rpn,lpn);
rpn->setch(0,bn);rpn->updata();lpn->updata();//把目标区间所在的子树接上
}
else if(bn)bn->rev^=1;
}num=0;show(root);
// print();
}
return 0;
}