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

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

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

转载于:https://www.cnblogs.com/largecube233/p/6797918.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值