洛谷P2286 [HNOI2004]宠物收养场(BZOJ1208)

博客介绍了洛谷P2286 [HNOI2004]宠物收养场问题的解决方案,重点讨论了如何利用平衡树进行求解。在实现过程中,博主分享了因数组大小设置不当导致的WA和RE错误,强调了在处理类似问题时应注意数组大小的设定,以及在平衡树中处理相同元素的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

洛谷P2286 [HNOI2004]宠物收养场(BZOJ1208)

平衡树

洛谷题目传送门
BZOJ题目传送门

本来1A的。。。没有膜WA了3发,数组开小了又RE了一发。。。

加一个标记表示当前是宠物树还是领养者树。如果当前读入的和标记一样就直接加进去,否则找前驱和后继比较后删去一个点。当树为空时改变标记。

没有用内存池数组要开80000啊。。。别被10000坑到了。。。血一样的教训。。。

代码(这里用Treap):

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 80000
using namespace std;
const int MOD=1e6;
struct node{
    int rnd,to[2],p,size;
    int w;
}t[N+5];
int m,nd,rt,fl;
long long ans;
void rtt(int &x,int fl){
    int s=t[x].to[fl];
    t[x].to[fl]=t[s].to[fl^1];
    t[s].to[fl^1]=x; t[s].size=t[x].size;
    t[x].size=t[t[x].to[0]].size+t[t[x].to[1]].size+t[x].p;
    x=s;
}
void nsrt(int &x,int w){
    if (!x){
        t[x=++nd].w=w; t[x].p=t[x].size=1;
        t[x].rnd=rand(); return;
    }
    t[x].size++;
    if (t[x].w==w) t[x].p++;
    else{
        int flag=t[x].w<w;
        nsrt(t[x].to[flag],w);
        if (t[t[x].to[flag]].rnd<t[x].rnd) rtt(x,flag);
    }
}
void dlt(int &x,int w){
    if (!x) return;
    if (t[x].w==w){ 
        if (t[x].p>1) { t[x].size--; t[x].p--; return; }
        if (!t[x].to[0]) { x=t[x].to[1]; return; }
        if (!t[x].to[1]) { x=t[x].to[0]; return; }
        int flag=t[t[x].to[0]].rnd<t[t[x].to[1]].rnd;
        rtt(x,flag^1),dlt(x,w);
    }
    else{
        t[x].size--;
        int flag=t[x].w<w;
        dlt(t[x].to[flag],w);
    }
}
int srch_frnt(int x,int w){
    if (!x) return -1;
    if (t[x].w==w) return w;
    if (t[x].w<w){
        int p=srch_frnt(t[x].to[1],w);
        if (~p) return p;
        return t[x].w;
    }
    else return srch_frnt(t[x].to[0],w);
}
int srch_bck(int x,int w){
    if (!x) return -1;
    if (t[x].w==w) return w;
    if (t[x].w>w){
        int p=srch_bck(t[x].to[0],w);
        if (~p) return p;
        return t[x].w;
    }
    else return srch_bck(t[x].to[1],w);
}
int main(){
    scanf("%d",&m);
    while (m--){
        int flag;int x;
        scanf("%d%d",&flag,&x);
        if (!t[rt].size) fl=flag;//如果当前树空改变标记
        if (flag^fl){//如果不相同则匹配后删除
            int p=srch_frnt(rt,x),q=srch_bck(rt,x);
            if ((p!=-1&&x-p<=q-x)||q==-1) (ans+=x-p)%=MOD,dlt(rt,p);
            if ((q!=-1&&q-x<x-p)||p==-1) (ans+=q-x)%=MOD,dlt(rt,q); 
        }
        else nsrt(rt,x);//否则直接加进去
    }
    return printf("%lld\n",ans),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值