洛谷$P$2286 宠物收养场 $[HNOI2004]$ $splay$

正解:$splay$

解题报告:

传送门!

$splay$板子,,,?

先考虑这题要实现些什么东西嘛$QwQ$

其实只要实现一个东西?就查询数列中与给定数字相差最小的数,显然用$splay$查询前驱后继,然后就没辣,,,?(哦还一个$insert$,,,$QwQ$

记得分类讨论下是人有剩还是宠物有剩就好,$over$

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char

const int N=1e5,mod=1000000,inf=1e9;
int rt,n,cnt=1,nod_cnt,as,a,b;
struct nod{int ch[2],val,sz,fa;il void pre(ri x,ri fat){ch[0]=ch[1]=0;val=x;sz=1;fa=fat;}}tr[N];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void pushup(ri x){tr[x].sz=tr[tr[x].ch[0]].sz+tr[tr[x].ch[1]].sz+1;}
il void rotate(ri x)
{
    ri fa=tr[x].fa,grdfa=tr[fa].fa;rb op1=tr[fa].ch[1]==x,op2=tr[grdfa].ch[1]==fa;
    tr[grdfa].ch[op2]=x;tr[x].fa=grdfa;
    tr[fa].ch[op1]=tr[x].ch[op1^1];tr[tr[x].ch[op1^1]].fa=fa;
    tr[fa].fa=x;tr[x].ch[op1^1]=fa;
    pushup(fa);pushup(x);
}
il void splay(ri x,ri goal)
{
    if(!x)return;
    while(tr[x].fa!=goal)
    {
        ri fa=tr[x].fa,grdfa=tr[fa].fa;
        if(grdfa!=goal)(tr[fa].ch[0]==x)^(tr[grdfa].ch[0]==fa)?rotate(x):rotate(fa);
        rotate(x);
    }
    if(!goal)rt=x;
}
il void insert(ri x)
{
    ri nw=rt,fa=0;
    while(nw)fa=nw,nw=tr[nw].ch[tr[nw].val<x];
    nw=++nod_cnt;if(fa)tr[fa].ch[tr[fa].val<x]=nw;tr[nw].pre(x,fa);
    splay(nw,0);
}
il void fd(ri x)
{
    ri nw=rt;if(!rt)return;
    while(tr[nw].ch[x>tr[nw].val] && x!=tr[nw].val)nw=tr[nw].ch[x>tr[nw].val];
    splay(nw,0);
}
il int ask_pr(ri x)
{
    fd(x);ri nw=rt;
    if(tr[nw].val<=x)return nw;
    nw=tr[nw].ch[0];
    while(tr[nw].ch[1])nw=tr[nw].ch[1];
    return nw;
}
il int ask_lst(ri x)
{
    fd(x);ri nw=rt;
    if(tr[nw].val>=x)return nw;
    nw=tr[nw].ch[1];
    while(tr[nw].ch[0])nw=tr[nw].ch[0];
    return nw;
}
il int ask_pr_yg(ri x)
{
    fd(x);ri nw=rt;
    if(tr[nw].val<x)return nw;
    nw=tr[nw].ch[0];
    while(tr[nw].ch[1])nw=tr[nw].ch[1];
    return nw;
}
il int ask_lst_yg(ri x)
{
    fd(x);ri nw=rt;
    if(tr[nw].val>x)return nw;
    nw=tr[nw].ch[1];
    while(tr[nw].ch[0])nw=tr[nw].ch[0];
    return nw;
}
il void delet(ri x)
{
    ri pr=ask_pr_yg(x),lst=ask_lst_yg(x);
    splay(pr,0);splay(lst,pr);
    tr[tr[rt].ch[1]].ch[0]=0;
}

int main()
{
//     freopen("2286.in","r",stdin);freopen("2286.out","w",stdout);
    n=read();insert(inf);insert(-inf);
    while(n--)
    {
        cnt+=a?1:-1;a=read(),b=read();
        if(!cnt){insert(b);continue;}
        if(cnt>0)
        {
            if(a){insert(b);continue;}
            ri pr=ask_pr(b),lst=ask_lst(b);
            if(abs(tr[lst].val-b)<abs(b-tr[pr].val))
            {
                as+=abs(tr[lst].val-b);as%=mod;
                delet(tr[lst].val);
            }
            else
            {
                as+=abs(b-tr[pr].val);as%=mod;
                delet(tr[pr].val);
            }
        }
        else
        {
            if(!a){insert(b);continue;}
            ri pr=ask_pr(b),lst=ask_lst(b);
            if(abs(tr[lst].val-b)<abs(b-tr[pr].val))
            {
                as+=abs(tr[lst].val-b);as%=mod;
                delet(tr[lst].val);
            }
            else
            {
                as+=abs(b-tr[pr].val);as%=mod;
                delet(tr[pr].val);
            }
        }
    }
    printf("%d\n",as);
    return 0;
}
View Code
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值