HDU 1890
这是我第一次接触Splay树时,所接触的代码。
那位大牛的博客我现在找不到了#。#。抱歉ing..
思路就是区间翻转,主要是将n个数通过树的先序访问保存下来。
这样旋转的时候就不会出现问题
代码:
//
// 1890.cpp
// ACM_HDU
//
// Created by ipqhjjybj on 13-8-27.
// Copyright (c) 2013年 ipqhjjybj. All rights reserved.
// 参考着别人Ac代码敲的
//
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
struct SplayTree{
const static int maxn=111111;
int n,tot,root;
map<int,int> Map;
int child[maxn][2];
int pre[maxn],size[maxn],flex[maxn];
int id[maxn];
struct node{
int id,val;
bool operator < (const node & tmp) const{
return val<tmp.val||(val==tmp.val&&id<tmp.id);
}
}in[maxn];
void Pushup(int &x){
size[x]=size[child[x][0]]+size[child[x][1]]+1;
}
void Pushdown(int &x){
if(flex[x]){
flex[x]=0;
flex[child[x][0]]^=1;
flex[child[x][1]]^=1;
swap(child[x][0],child[x][1]);
}
}
void Del_root(){
int t=root;
if(child[root][1]){
root=child[root][1];
Select(1,0);
child[root][0]=child[t][0];
if(child[t][0]) pre[child[t][0]]=root;
}else
root=child[root][0];
pre[root]=0;
Pushup(root);
}
// c==0 左旋 , c==1 右旋
inline void Rotate(int x, int c) { // 旋转, c=0 左旋, c=1 右旋
int y = pre[x];
Pushdown(y);
Pushdown(x);
child[y][!c] = child[x][c];
if ( child[x][c] ) pre[ child[x][c] ] = y;
pre[x] = pre[y];
if ( pre[y] ) child[ pre[y] ][ child[pre[y]][1] == y ] = x;
child[x][c] = y;
pre[y] = x;
Pushup(y);
}
void Splay(int x,int f){
// puts("fuck Splay");
Pushdown(x);
while(pre[x]!=f){
// printf("f=%d pre[%d]=%d\n",f,x,pre[x]);
int y=pre[x],z=pre[y];
Pushdown(z),Pushdown(y),Pushdown(x);
if(pre[pre[x]]==f){
Rotate(x,child[pre[x]][0]==x);
}else{
if ( child[z][0] == y ) {
if ( child[y][0] == x )
Rotate(y, 1), Rotate(x, 1);
else
Rotate(x, 0), Rotate(x, 1);
}
else {
if ( child[y][0] == x )
Rotate(x, 1), Rotate(x, 0);
else
Rotate(y, 0), Rotate(x, 0);
}
}
}
Pushup(x);
if(f==0) root=x;
}
void Select(int k,int f){
int x=root;
while(1){
Pushdown(x);
if(k==size[child[x][0]]+1)
break;
if(k<=size[child[x][0]])
x=child[x][0];
else{
k-=size[child[x][0]]+1;
x=child[x][1];
}
}
Splay(x,f);
}
void Newnode(int &x,int f){
//puts("fuck newnode");
x=++tot;
child[x][0]=child[x][1]=0;
pre[x]=f;
flex[x]=0;
size[x]=1;
}
void Build(int &x,int l,int r,int f){
if(l>r)return;
int mid=(l+r)>>1;
//puts("Fuck(Build)");
Newnode(x,f);
Map[id[mid]]=x;
Build(child[x][0],l,mid-1,x);
Build(child[x][1],mid+1,r,x);
Pushup(x);
}
void init(int _n){
n=_n; Map.clear(); root=tot=0;
pre[0]=child[0][0]=child[0][1]=0;
size[0]=flex[0]=0;
for(int i=1;i<=n;i++){
scanf("%d",&in[i].val);
in[i].id=i;
}
sort(in+1,in+1+n);
for(int i=1;i<=n;i++)
id[in[i].id]=i;
Map[id[1]]=1;
Map[id[n]]=2;
Newnode(root,0);
Newnode(child[root][1],root);
Build(child[child[root][1]][0],2,n-1,child[root][1]);
Pushup(child[root][1]);
Pushup(root);
}
void solve(int n){
for(int i=1;i<=n;i++){
//printf("i=%d\n",i);
//printf("Map[%d]=%d\n",i,Map[i]);
Splay(Map[i],0);
//printf("root=%d\n",root);
printf("%d%c",i+size[child[root][0]],i==n?'\n':' ');
flex[child[root][0]]^=1;
Del_root();
}
}
}spt;
int main(){
int n;
while(scanf("%d",&n)&&n){
if(n==1){scanf("%*d");puts("1");continue;}
spt.init(n);
spt.solve(n);
}
return 0;
}
HDU 3487
别人都说这是水题。。
设计到Splay的基本操作,区间翻转及区间插入。。
对[l,r]这段区间,要想获得的话,先将l-1这个节点翻转到根节点,再把r+1这个节点翻转到根节点之下。
这样KeyTree child[child[root][1]][0] 所表示的那段就是区间[l,r]了。 之后再进行区间的删除跟插入。
找到要插入的区间,比如插到i之后,就先把i旋转到根节点,然后然后把i的右子树中的最小的那个点旋转到根下面,这样这个最小点的左节点就是空的节点,可以插入那段区间了。
翻转的操作反而更加简单, 只用获得节点,传递一个修改的标记的就好了。
http://blog.csdn.net/acm_cxlove/article/details/7795244 原博客
代码:
//
// 3487.cpp
// ACM_HDU
//
// Created by ipqhjjybj on 13-9-6.
// Copyright (c) 2013年 ipqhjjybj. All rights reserved.
// 先看完别人代码。后来凭记忆敲的Ac代码
//
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<algorithm>
#define N 300015
#define inf 1<<29
#define MOD 100000007
#define LL long long
#define _match(a,b) ((a)==(b))
#define Key_value ch[ch[root][1]][0]
using namespace std;
int n,q;
int size[N],pre[N],key[N],num[N],rev[N];
int ch[N][2],tot,root,node[N];
void Push_Up(int &t){
size[t]=size[ch[t][0]]+size[ch[t][1]]+1;
}
void Push_Down(int &t){
if(rev[t]){
swap(ch[t][0],ch[t][1]);
rev[ch[t][0]]^=1;
rev[ch[t][1]]^=1;
rev[t]=0;
}
}
void NewNode(int &t,int k,int father){
t=++tot;
pre[t]=father;
key[t]=k;
rev[t]=0;
ch[t][0]=ch[t][1]=0;
}
void Build(int &t,int l,int r,int father){
if(l>r)return;
int mid=(l+r)>>1;
NewNode(t,mid,father);
Build(ch[t][0],l,mid-1,t);
Build(ch[t][1],mid+1,r,t);
Push_Up(t);
}
void Init(){
root=tot=0;
ch[root][0]=ch[root][1]=pre[root]=rev[root]=size[root]=0;
NewNode(root,-1,0);
NewNode(ch[root][1],-1,root);
size[root]=2;
Build(Key_value,1,n,ch[root][1]);
Push_Up(ch[root][1]);
Push_Up(root);
}
void Rotate(int x,int c){ // c==0左旋,c==1右旋
int y=pre[x];
Push_Down(y);
Push_Down(x);
ch[y][!c]=ch[x][c];
pre[ch[x][c]]=y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1]==y]=x;
pre[x]=pre[y];
ch[x][c]=y;
pre[y]=x;
Push_Up(y);
}
void Splay(int x,int father){
Push_Down(x);
while(pre[x]!=father){
int y=pre[x],z=pre[y];
Push_Down(z),Push_Down(y),Push_Down(z);
if(pre[y]==father){
Rotate(x,ch[y][0]==x);
}else{
if(ch[z][0]==y){
if(ch[y][0]==x)
Rotate(y,1),Rotate(x,1);
else Rotate(x,0),Rotate(x,1);
}else{
if(ch[y][0]==x)
Rotate(x,1),Rotate(x,0);
else Rotate(y,0),Rotate(x,0);
}
}
}
Push_Up(x);
if(father==0) root=x;
}
int Get_Kth(int t,int k){
Push_Down(t);
if(size[ch[t][0]]==k-1)
return t;
else if(size[ch[t][0]]>=k)
return Get_Kth(ch[t][0],k);
else return Get_Kth(ch[t][1],k-size[ch[t][0]]-1);
}
int Min_Value(int t){
Push_Down(t);
while(ch[t][0]){
t=ch[t][0];
Push_Down(t);
}
return t;
}
void Reversal(int a,int b){
a=Get_Kth(root,a);
b=Get_Kth(root,b+2);
Splay(a,0);
Splay(b,root);
rev[Key_value]^=1;
}
void Cut(int a,int b,int c){
int x=Get_Kth(root,a);
int y=Get_Kth(root,b+2);
Splay(x,0);
Splay(y,root);
int tmp=Key_value;
Key_value=0;
Push_Up(ch[root][1]);
Push_Up(root);
int cm=Get_Kth(root,c+1);
Splay(cm,0);
int mi=Min_Value(ch[root][1]);
Splay(mi,root);
Key_value=tmp;
pre[Key_value]=ch[root][1];
Push_Up(ch[root][1]);
Push_Up(root);
}
int cnt;
void InOrder(int r){
if(r==0)
return;
Push_Down(r);
InOrder(ch[r][0]);
if(cnt>=1&&cnt<=n){
if(cnt>1)printf(" ");
printf("%d",key[r]);
}
cnt++;
InOrder(ch[r][1]);
}
int main(){
while(scanf("%d%d",&n,&q)!=EOF){
if(n==-1&&q==-1)
break;
Init();
while(q--){
char str[10];
int a,b,c;
scanf("%s",str);
if(str[0]=='C'){
scanf("%d%d%d",&a,&b,&c);
Cut(a,b,c);
}
else{
scanf("%d%d",&a,&b);
Reversal(a,b);
}
}
cnt=0;
InOrder(root);
printf("\n");
}
return 0;
}
HDU 3436
这道题是离散化数据来进行Splay。 非常感谢这位大牛的代码。
很有借鉴的意义。。 区间的离散, 把需要的点单独存,end跟beg都为1,不然就保存的时候, 1到a1-1就保存成 beg=1, end=a1-1这样类似的。。
理解后就感觉不难了。
原博客:http://blog.sina.com.cn/s/blog_6c7729450100uvye.html
代码:
//
// 3436.cpp
// ACM_HDU
//
// Created by ipqhjjybj on 13-9-7.
// Copyright (c) 2013年 ipqhjjybj. All rights reserved.
// 先看完别人代码的。。
//
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 222222;
int n,q,k,N;
char re[MAXN];
int req[MAXN],a[MAXN],na,beg[MAXN],end[MAXN];
int num[MAXN],pre[MAXN],ch[MAXN][2],root;
void flow(int x){
num[x]=num[ch[x][0]]+num[ch[x][1]]+end[x]-beg[x]+1;
}
inline void rotate(int n)
{
int t=pre[n];
bool isr=(ch[t][1]==n);
ch[t][isr]=ch[n][!isr],pre[ch[n][!isr]]=t;
pre[n]=pre[t],ch[pre[t]][ch[pre[t]][1]==t]=n;
pre[t]=n,ch[n][!isr]=t;
flow(t);
}
inline void splay(int n,int goal)
{
int f,ff;
while(pre[n]!=goal)
{
f=pre[n],ff=pre[f];
if(goal==ff)
rotate(n);
else if((ch[ff][1]==f)==(ch[f][1]==n))
rotate(f),rotate(n);
else
rotate(n),rotate(n);
}
flow(n);
if(!goal)
root=n;
}
void Top(int t){
splay(t,0);
int x=ch[t][1];
while(ch[x][0])
x=ch[x][0];
splay(x,t);
ch[x][0]=ch[t][0],pre[ch[t][0]]=x;
ch[t][0]=0;
//因为算法的特殊性.root不能变为t;
flow(t);
}
int Rank(int n){
int t=root;
while(1){
if(num[ch[t][0]]<n&&num[ch[t][0]]+end[t]-beg[t]+1>=n)
break;
if(n<=num[ch[t][0]])
t=ch[t][0];
else {
n-=num[ch[t][0]]+end[t]-beg[t]+1,t=ch[t][1];
}
}
int ans=beg[t]+n-1-num[ch[t][0]];
splay(t,0);
return ans;
}
int Query(int x){
splay(x,0);
return num[ch[x][0]]+1;
}
int Bisearch(int n)
{
int l=1,r=N,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(beg[mid]>n)
r=mid-1;
else if(end[mid]<n)
l=mid+1;
else
return mid;
}
return l;
}
int main(){
int t,tt=0,val,i,j;
char str[10];
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&q);
k=0;
na=0;
for(i=0;i<q;i++){
scanf("%s %d",str,&val);
re[k]=str[0],req[k++]=val;
if(str[0]=='T'){
a[na++]=val;
}
}
sort(a,a+na);
for(j=i=1;i<na;i++)
if(a[i]!=a[i-1])
a[j++]=a[i];
na=j;j=1;
if(a[0]>1){
beg[j]=1,end[j++]=a[0]-1;
}
for(i=0;i<na;i++){
end[j]=beg[j]=a[i],j++;
if(i<na-1){
if(a[i]+1<a[i+1]){
beg[j]=a[i]+1,end[j]=a[i+1]-1;
j++;
}
}else{
beg[j]=a[i]+1,end[j]=n,j++;
}
}
beg[j]=end[j]=n+1;j++;
memset(ch,0,sizeof(int)*(j+2)*2);
num[0]=0,N=j-1;
for(i=1;i<=N;i++){
num[i]=num[i-1]+end[i]-beg[i]+1;
pre[i-1]=i,ch[i][0]=i-1;
}pre[N]=0;
root=N;
printf("Case %d:\n",++tt);
for(i=0;i<k;i++){
if(re[i]=='T'){
Top(Bisearch(req[i]));
}else if(re[i]=='R'){
printf("%d\n",Rank(req[i]));
}else{
j=Bisearch(req[i]);
printf("%d\n",Query(j)+req[i]-beg[j]);
}
}
}
return 0;
}