您的位置:首页 > 大数据 > 人工智能

HDOJ 3487 Play with Chain【splay】

2014-02-13 12:59 281 查看
题目: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
,*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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: