【HNOI2004】宠物收养所(Splay删除前驱后继)

这篇博客主要介绍了如何使用Splay数据结构来解决HNOI2004比赛中关于宠物收养所的问题。内容涉及到Splay的特殊操作,包括删除节点的前驱和后继节点,并强调了处理边界条件的重要性,如返回值为-INF的情况以及INF的定义。
摘要由CSDN通过智能技术生成

用Splay按照题意模拟即可

注意边界情况的特判 pre返回的是-INF!以及INF的取值!

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define ll long long
const int N=80005;
const int mod=1000000;
const int INF=2147483600;
using namespace std;
template<class T>
inline void read(T &x)
{
    x=0; int f=1;
    static char ch=getchar();
    while(!isdigit(ch))	{if(ch=='-') f=-1;ch=getchar();} 
    while(isdigit(ch))	x=x*10+ch-'0',ch=getchar();
    x*=f;
}
int n,k,cnt,root,tot;
struct Tree
{
    int fa,lc,rc,size;
    ll val;
}t[N];
inline int which(int u){return t[t[u].fa].rc==u;} 
inline void pushup(int u){t[u].size=t[t[u].lc].size+t[t[u].rc].size+1;}
inline void Rotate(int u)
{
    int v=t[u].fa,w=t[v].fa;
    int b=(t[v].rc==u)?t[u].lc:t[u].rc;
    t[v].fa=u; t[u].fa=w;
    if(b)	t[b].fa=v;
    if(w)	(t[w].lc==v?t[w].lc:t[w].rc)=u;
    if(t[v].rc==u) t[u].lc=v,t[v].rc=b;
    else t[u].rc=v,t[v].lc=b;
    pushup(v); pushup(u);
}
inline void Splay(int u,int tar)
{
    while(t[u].fa!=tar)
    {
        if(t[t[u].fa].fa!=tar)
        {
            if(which(u)==which(t[u].fa)) Rotate(t[u].fa);
            else Rotate(u);
        }
        Rotate(u);
    }
    if(!tar)	root=u;
}
inline void insert(ll val)
{
    int u=root,v=0,dir;
    while(u)
    {
        v=u;
        if(val<t[u].val) dir=0,u=t[u].lc;
        else dir=1,u=t[u].rc;
    }
    u=++tot;
    t[u].fa=v; t[u].val=val; t[u].size=1;
    if(v) (dir==0?t[v].lc:t[v].rc)=u;
    Splay(u,0);
}
inline int find(ll val)
{
    int u=root;
    while(u)
    {
        if(val==t[u].val)	break;
        if(val<t[u].val)	u=t[u].lc;
        else u=t[u].rc;
    }
    if(u) Splay(u,0);
    return u;
}
inline int findmax(int u)
{
    while(t[u].rc) u=t[u].rc;
    return u;
}
inline void Delete(ll val)
{
    int u=find(val);
    if(!t[u].lc||!t[u].rc)	
    {
        root=t[u].lc+t[u].rc;
        t[root].fa=0;
    }
    else
    {
        int v=findmax(t[root].lc);
        Splay(v,u);
        t[v].rc=t[u].rc; t[t[u].rc].fa=v; t[v].fa=0; root=v;
        pushup(root);
    }
}
inline ll pre(ll val)
{
    int u=root,ans=0;
    while(u)
    {
        if(val>t[u].val) ans=u,u=t[u].rc;
        else u=t[u].lc;
    }
    return (ans==0?-INF:t[ans].val);
}
inline ll sub(ll val)
{
    int u=root,ans=0;
    while(u)
    {
        if(val<t[u].val) ans=u,u=t[u].lc;
        else u=t[u].rc;
    }
    return (ans==0?INF:t[ans].val);
}
int main()
{
    read(n);
    ll ans=0;
    int a; ll b;
    for(int i=1;i<=n;i++)
    {
        read(a); read(b);
        if(cnt==0)
        {
            insert(b);
            k=a;
            cnt++;
        }
        else if((k==a))	 insert(b),cnt++;//同一类
        else
        {
            ll last=pre(b),next=sub(b);
            if(b-last==next-b)
            {
                Delete(last);
                ans=(ans+b-last)%mod;
            }
            else
            {
                if(b-last<next-b)	Delete(last),ans=(ans+b-last)%mod;
                else Delete(next),ans=(ans+next-b)%mod; 
            }
            cnt--;
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值