您的位置:首页 > 其它

[CODEVS1343][HNOI]蚱蜢(平衡树splay)

2016-03-23 23:23 399 查看

题目描述

传送门

题解

在线段树即将写吐之际改了平衡树,没想到吃屎程度不减反增。

调了一晚上,想不出哪里出错了,最终的原因是一个小地方。

思路是按照位置存储,每一次找位置(find) ,维护maxn。求区间的时候将区间的前驱和后继splay到根和根的右儿子,添加的时候把要插在两个结点中间的两个结点splay到根和根的右儿子,删除的时候把结点的前驱和后继splay到根和根的右儿子,这样我们就可以对根的右儿子的左儿子进行操作来达到目的。

要注意的是,蚱蜢跳啊跳时insert和del的顺序,这个很重要,因为在平衡树中是按照位置存储的,每一次需要find到它的位置,del之后位置就不存在了。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=2e5+5;
const int INF=2e9;

int n,m,st,cnt;
int a[max_n];
int root,sz;
int ch[max_n][2],f[max_n],size[max_n],maxn[max_n],key[max_n];

inline bool get(int x){
return ch[ f[x] ][1]==x;
}

inline void update(int x){
if (x){
size[x]=1;
maxn[x]=key[x];
if (ch[x][0]){
size[x]+=size[ ch[x][0] ];
maxn[x]=max(maxn[x],maxn[ ch[x][0] ]);
}
if (ch[x][1]){
size[x]+=size[ ch[x][1] ];
maxn[x]=max(maxn[x],maxn[ ch[x][1] ]);
}
}
}

inline void rotate(int x){
int old=f[x],oldf=f[old],which=get(x);

ch[old][which]=ch[x][which^1];
f[ ch[old][which] ]=old;

ch[x][which^1]=old;
f[old]=x;

f[x]=oldf;
if (oldf)
ch[oldf][ ch[oldf][1]==old ]=x;

update(old);
update(x);
}

inline void splay(int x,int tar){
for (int fa;(fa=f[x])!=tar;rotate(x))
if (f[fa]!=tar)
rotate( (get(x)==get(fa)) ?fa:x );
if (!tar) root=x;
}

inline int build(int l,int r,int fa){
if (l>r) return 0;
int mid=(l+r)>>1;

int now=++sz;
key[now]=a[mid]; maxn[now]=a[mid]; size[now]=1; f[now]=fa;
int lch=build(l,mid-1,now);
int rch=build(mid+1,r,now);
ch[now][0]=lch;
ch[now][1]=rch;

update(now);
return now;
}

//Find the xth number
inline int find(int x){
int now=root;
while (1){
if (ch[now][0]&&x<=size[ ch[now][0] ])
now=ch[now][0];

else{
int temp=1;
if (ch[now][0])
temp+=size[ ch[now][0] ];
if (x<=temp) return now;
x-=temp;
now=ch[now][1];
}
}
}

//Find the xth number's val
inline int findval(int x){
int now=root;
while (1){
if (ch[now][0]&&x<=size[ ch[now][0] ])
now=ch[now][0];

else{
int temp=1;
if (ch[now][0])
temp+=size[ ch[now][0] ];
if (x<=temp) return key[now];
x-=temp;
now=ch[now][1];
}
}
}

inline void Query(int L,int R){
//L-1 R+1
int aa=find(L);
int bb=find(R+2);
splay(aa,0);
splay(bb,aa);

int ans=maxn[ ch[ ch[root][1] ][0] ];
printf("%d\n",ans);

update(ch[root][1]);
update(root);
}

//Insert val to x
inline void Insert(int x,int val){
//x-1 x
int aa=find(x);
int bb=find(x+1);
splay(aa,0);
splay(bb,aa);

ch[ ch[root][1] ][0]=++sz;
f[sz]=ch[root][1];
ch[sz][0]=ch[sz][1]=0;
size[sz]=1;
key[sz]=val;
maxn[sz]=val;

update(f[sz]);
update(root);
}

inline void del(int x){
//x-1 x+1
int aa=find(x);
int bb=find(x+2);
splay(aa,0);
splay(bb,aa);

ch[ ch[root][1] ][0]=0;

update(ch[root][1]);
update(root);
}

int main(){
scanf("%d%d",&n,&m);
a[1]=-INF; a[n+2]=INF;
for (int i=1;i<=n;++i)
scanf("%d",&a[i+1]);

root=build(1,n+2,0);

for (int i=1;i<=m;++i){
scanf("%d",&st);
char c=getchar();
while (c!='L'&&c!='D') c=getchar();
scanf("%d",&cnt);

if (c=='L'){
//query
int L=st-cnt;
int R=st-1;
Query(L,R);

//change
int val=findval(st+1);//st
del(st);
Insert(L,val);
}
else{
//query
int L=st+1;
int R=st+cnt;
Query(L,R);

//change
int val=findval(st+1);//st
del(st);
Insert(R,val);
}
}
}


总结

①添加和删除一定要想好。

②平衡树还是要继续熟悉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: