Splay伸展树,十分强大的数据结构,学习了好几天,可是做题还是很难独立敲出来QAQ
感谢:http://blog.csdn.net/crazy_ac/article/details/8034264 此篇文章的作者,代码风格我感觉灰常好!
等我熟练掌握了,我也写篇总结~~
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1208
题意:
中文题面,有宠物和人,每个单位都有一个与其他单位不同的值(正),如果现在有宠物,来了一个人,人取走和他的值最接近的宠物(如果有两个选值小的),如果现在有人,来了一个宠物,和它值最接近的人(如果有两个选值小的)取走它.求每次带宠物走两个单位的值的差的绝对值的总和.
分析:
平衡树入门题,用Splay写了
人和宠物其实是一样的,建立一颗树即可,如果树上节点是人,那么来一个宠物,就找这个值得前驱节点和后继节点,看一下哪个节点的值接近,那么求和,然后把接近的节点删掉,可以旋转到根,然后再删。
代码:
#include<cstdio>
#include<cstdlib>
const int mod =1000000;
const int inf = ~0u>>2;
#define L ch[x][0]
#define R ch[x][1]
#define KT (ch[ ch[rt][1] ][0])
const int maxn = 1e6+9;
int lim;
struct SplayTree {
int sz[maxn];
int ch[maxn][2];
int pre[maxn];
int rt,top;
inline void up(int x) {
sz[x] = cnt[x] + sz[ L ] + sz[ R ];
}
inline void Rotate(int x,int f) {
int y=pre[x];
ch[y][!f] = ch[x][f];
pre[ ch[x][f] ] = y;
pre[x] = pre[y];
if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x;
ch[x][f] = y;
pre[y] = x;
up(y);
}
inline void Splay(int x,int goal) { //将x旋转到goal的下面
while(pre[x] != goal) {
if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x);
else {
int y=pre[x],z=pre[y];
int f = (ch[z][0]==y);
if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
else Rotate(y,f),Rotate(x,f);
}
}
up(x);
if(goal==0) rt=x;
}
inline void RTO(int k,int goal) { //将第k位数旋转到goal的下面
int x=rt;
while(sz[ L ] != k-1) {
if(k < sz[ L ]+1) x=L;
else {
k-=(sz[ L ]+1);
x = R;
}
}
Splay(x,goal);
}
inline void vist(int x) {
if(x) {
printf("结点%2d : 左儿子 %2d 右儿子 %2d val:%2d sz=%d cnt:%d\n",x,L,R,val[x],sz[x],cnt[x]);
vist(L);
vist(R);
}
}
void debug() {
puts("");
vist(rt);
puts("");
}
inline void Newnode(int &x,int c,int f) {
x=++top;
L = R = 0;
pre[x] = f;
sz[x]=1;
cnt[x]=1;
val[x] = c;
}
inline void init() {
ans=0;
type=-1;
ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
rt=top=0;
cnt[0]=0;
Newnode(rt,-inf,0);
Newnode(ch[rt][1],inf,rt);
sz[rt]=2;
}
inline void Insert(int &x,int key,int f) {
if(!x) {
Newnode(x,key,f);
Splay(x,0);//注意插入完成后splay
return ;
}
if(key==val[x]) {
cnt[x]++;
sz[x]++;
Splay(x,0);//注意插入完成后splay
return ;
} else if(key<val[x]) {
Insert(L,key,x);
} else {
Insert(R,key,x);
}
up(x);
}
void Del_root() { //删除根节点
int t=rt;
if(ch[rt][1]) {
rt=ch[rt][1];
RTO(1,0);
ch[rt][0]=ch[t][0];
if(ch[rt][0]) pre[ch[rt][0]]=rt;
} else rt=ch[rt][0];
pre[rt]=0;
up(rt);
}
void findpre(int x,int key,int &ans) { //找前驱节点
if(!x) return ;
if(val[x] <= key) {
ans=x;
findpre(R,key,ans);
} else
findpre(L,key,ans);
}
void findsucc(int x,int key,int &ans) { //找后继节点
if(!x) return ;
if(val[x]>=key) {
ans=x;
findsucc(L,key,ans);
} else
findsucc(R,key,ans);
}
void solve() {
int a,b,x,y;
scanf("%d%d",&a,&b);
if(a==type||sz[rt]==2) {
Insert(rt,b,0);
type=a;
} else {
findpre(rt,b,x);
findsucc(rt,b,y);
if(abs(val[x]-b)<=abs(val[y]-b)) {
ans+=abs(val[x]-b);
ans%=mod;
Splay(x,0);
Del_root();
} else {
ans+=abs(val[y]-b);
ans%=mod;
Splay(y,0);
Del_root();
}
}
}
int cnt[maxn];
int val[maxn];
int type;
int ans;
} spt;
//bzoj 1208
int main() {
// freopen("f.txt","r",stdin);
int n,op,x;
scanf("%d",&n);
spt.init();
while(n--)spt.solve();
printf("%d\n",spt.ans);
return 0;
}