https://www.luogu.org/problem/show?pid=2286#sub
我很高兴啊,我没做多久就做出来了,当然也没调多久;
虽然一开始del哪里出了写问题,但是做了这两道题,spaly的基本操作,我差不多掌握了;
对于前驱后继,我又掌握了一遍;
不多说了;
我代码里其实不用维护节点个数的;
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
struct SP{
int l,r,s,v,fa;
}sp[80001];
int n,m,x,y,z,rt,nn,xx,yy,mo=1e6;
int animal,human;
long long ans;
void up(int x){sp[x].s=sp[sp[x].l].s+sp[sp[x].r].s+1;}
void zig(int x){
int y=sp[x].r;
if(rt==x)rt=y;else
if(sp[sp[x].fa].l==x)sp[sp[x].fa].l=y;else sp[sp[x].fa].r=y;
sp[y].fa=sp[x].fa;
sp[x].r=sp[y].l;
sp[sp[y].l].fa=x;
sp[y].l=x;
sp[x].fa=y;
sp[y].s=sp[x].s;
up(x);
}
void zag(int x){
int y=sp[x].l;
if(rt==x)rt=y;else
if(sp[sp[x].fa].l==x)sp[sp[x].fa].l=y;else sp[sp[x].fa].r=y;
sp[y].fa=sp[x].fa;
sp[x].l=sp[y].r;
sp[sp[y].r].fa=x;
sp[y].r=x;
sp[x].fa=y;
sp[y].s=sp[x].s;
up(x);
}
void splay(int x,int k){
while(sp[x].fa!=k){
int y=sp[x].fa,z=sp[y].fa;
if(z!=k)
if((sp[z].l==y)^(sp[y].l==x))
if(sp[y].l==x)zag(y);else zig(y);else
if(sp[z].l==y)zag(z);else zig(z);
y=sp[x].fa;
if(sp[y].l==x)zag(y);else zig(y);
}
}
void insert(int x){
if(!rt){sp[++nn].v=x;sp[nn].s=1;rt=nn;return;}
int k=rt,kk;
while(k){
kk=k;sp[k].s++;
if(x>sp[k].v)k=sp[k].r;else k=sp[k].l;
}
sp[++nn].v=x; sp[nn].s=1; sp[nn].fa=kk;
if(x>sp[kk].v)sp[kk].r=nn;else sp[kk].l=nn;
splay(nn,sp[rt].fa);
}
int qian(int k,int x){
if(!k)return -1;
if(sp[k].v<x){
int y=qian(sp[k].r,x);
if(y==-1)return k; return y;
}
if(sp[k].v>=x)return qian(sp[k].l,x);
}
int hou(int k,int x){
if(!k)return -1;
if(sp[k].v>x){
int y=hou(sp[k].l,x);
if(y==-1)return k; return y;
}
if(sp[k].v<=x)return hou(sp[k].r,x);
}
void del(int x){
int xx=qian(rt,sp[x].v),yy=hou(rt,sp[x].v);
if(xx==-1&&yy==-1)rt=0;else
if(xx==-1){
splay(yy,sp[rt].fa);
sp[rt].s--;
sp[rt].l=0;
}else
if(yy==-1){
splay(xx,sp[rt].fa);
sp[rt].s--;
sp[rt].r=0;
}else{
splay(xx,sp[rt].fa);
splay(yy,rt);
sp[rt].s--;
sp[sp[rt].r].s--;
sp[sp[rt].r].l=0;
}
}
int find(int k,int x){
if(!k)return 0;
if(sp[k].v==x)return k;
if(sp[k].v<x)return find(sp[k].r,x);
return find(sp[k].l,x);
}
int main()
{
scanf("%d",&m);
while(m--){
scanf("%d%d",&y,&x);
if(y)
if(!animal){
insert(x);
human++;
}else{
animal--;
int f=find(rt,x);
if(f){del(f);continue;}
xx=qian(rt,x);
yy=hou(rt,x);
if(yy==-1){ans+=x-sp[xx].v;del(xx);}else
if(xx==-1){ans+=sp[yy].v-x;del(yy);}else
if(x-sp[xx].v<=sp[yy].v-x)
{ans+=x-sp[xx].v;del(xx);}else
{ans+=sp[yy].v-x;del(yy);}
}
else
if(!human){
insert(x);
animal++;
}else{
human--;
int f=find(rt,x);
if(f){del(f);continue;}
xx=qian(rt,x);
yy=hou(rt,x);
if(yy==-1){ans+=x-sp[xx].v;del(xx);}else
if(xx==-1){ans+=sp[yy].v-x;del(yy);}else
if(x-sp[xx].v<=sp[yy].v-x)
{ans+=x-sp[xx].v;del(xx);}else
{ans+=sp[yy].v-x;del(yy);}
}
ans%=mo;
}
printf("%d",ans);
}
议论:关于spaly的del;
这个是标准del;
void del(int x){
int xx=qian(rt,sp[x].v),yy=hou(rt,sp[x].v);
if(xx==-1&&yy==-1)rt=0;else
if(xx==-1){
splay(yy,sp[rt].fa);
sp[rt].s--;
sp[rt].l=0;
}else
if(yy==-1){
splay(xx,sp[rt].fa);
sp[rt].s--;
sp[rt].r=0;
}else{
splay(xx,sp[rt].fa);
splay(yy,rt);
sp[rt].s--;
sp[sp[rt].r].s--;
sp[sp[rt].r].l=0;
}
}
就是把x的前驱后继找出来搞,我们可以在整个区间前后加一个空节点,那我们就不用特判找不到前驱的情况了;
但我有怎么一个想法;
我们假如要删除x节点,我们不断通过旋转,把x旋转到底层,就直接把x删掉就好了;
void del(int x){
for(int k=x;k;k=sp[k].fa)sp[k].s--;
while(sp[x].l&&sp[x].r){
zag(x);
sp[sp[x].fa].s--;
}
if(x==rt)rt=sp[x].l+sp[x].r;else
if(sp[sp[x].fa].r==x)sp[sp[x].fa].r=sp[x].l+sp[x].r;else sp[sp[x].fa].l=sp[x].l+sp[x].r;
sp[sp[x].l+sp[x].r].fa=sp[x].fa;
}
可是这样三个点死循环;
为什么?