spaly-洛谷P2286 [HNOI2004]宠物收养场

来源:互联网 发布:ubuntu 设置ip地址 编辑:程序博客网 时间:2024/04/29 09:02

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;}

可是这样三个点死循环;
为什么?

0 0
原创粉丝点击