【codevs1285】【BZOJ1208】宠物收养所,splay练习

传送门1
传送门2
写在前面:我自己也会被写进机房大事记……
思路:很裸的splay练习,只涉及查前驱后继和删除操作,加一个标记记录现在是宠物多还是人多即可
注意:
1.查询和调用前驱后继时可能两者同时存在,记得判断一下
2.不知道为什么用bool型做树的标记时总是自己莫名改值,害我调了好久
代码:

#include<bits/stdc++.h>
#define mod 1000000
int n,x,tot,root,ans;
int hand,flag;
struct os
{
    int data,fa,left,right,sz;
}a[100010];
int in()
{
    int f=1,t=0;
    char ch=getchar();
    while (ch>'9'||ch<'0')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9') t=t*10+ch-'0',ch=getchar();
    return f*t;
}
void made(int x)
{
    a[++tot].data=x;
    a[tot].sz=1;
}
void ct(int now)
{
    a[now].sz=a[now].left+a[now].right+1;
}
void rorate(int now,bool flag)
{
    int pa=a[now].fa;
    if (flag)
    {
        a[pa].left=a[now].right;
        if (a[now].right)a[a[now].right].fa=pa;
        if (a[pa].fa)
        {
            if (a[a[pa].fa].left==pa) a[a[pa].fa].left=now;
            else a[a[pa].fa].right=now;
        }
        a[now].fa=a[pa].fa;
        a[pa].fa=now;
        a[now].right=pa;
    }
    else
    {
        a[pa].right=a[now].left;
        if (a[now].left)a[a[now].left].fa=pa;
        if (a[pa].fa) 
        { 
            if (a[a[pa].fa].left==pa) a[a[pa].fa].left=now;
            else a[a[pa].fa].right=now;
        } 
        a[now].fa=a[pa].fa;
        a[pa].fa=now;
        a[now].left=pa;
    }
    ct(pa);
    ct(now);
}
void splay(int x,int goal)
{
    int y;
    while (a[x].fa!=goal)
    {
        y=a[x].fa;
        if (a[y].fa==goal)
        {
            if (a[y].left==x) rorate(x,1);
            else rorate(x,0);
        }
        else if (y==a[a[y].fa].left)
        {
            if (a[y].left==x) rorate(y,1);
            else rorate(x,0);
            rorate(x,1);
        }
        else
        {
            if (a[y].right==x) rorate(y,0);
            else rorate(x,1);
            rorate(x,0);
        }
    }
    if (!goal) root=x;
}
void insert(int x)
{
    made(x);a[tot].data=x;
    if (!root) {root=tot;return;}
    int now=root;
    while (now)
    {
        if (x<a[now].data)
        {
            if (!a[now].left) {a[now].left=tot;a[tot].fa=now;break;}
            else now=a[now].left;
        }
        else
        {
            if (!a[now].right) {a[now].right=tot;a[tot].fa=now;break;}
            else now=a[now].right;
        }
    }
    splay(tot,0);
}
int find(int x)
{
    int now=root;
    while (now)
    {
        if (a[now].data==x) return now;
        else if (a[now].data>x) now=a[now].left;
        else now=a[now].right;
    }
    return 0;
}
int find_max(int now)
{
    if (!now) return 0;
    while (now)
    {
        if (a[now].right) now=a[now].right;
        else return now;
    }
}
bool del(int now)
{
    splay(now,0);
    if (!a[now].left&&!a[now].right){root=0;return 1;}
    else if (!a[now].left)
    {
        a[a[now].right].fa=0;
        root=a[now].right;
    }
    else if (!a[now].right)
    {
        a[a[now].left].fa=0;
        root=a[now].left;
    }
    else
    {
        int child=find_max(a[now].left);
        splay(child,root);
        root=child;
        a[child].right=a[now].right;
        a[a[now].right].fa=child;
        a[child].fa=0;
        ct(child);
    }
    return 1;
}
int find_next_max(int x)
{
    int now=root,k=0;
    while (now)
    {
        if (a[now].data>x)
            k=(a[k].data>a[now].data||!k)?now:k,
            now=a[now].left;
        else now=a[now].right;
    }
    if (k) splay(k,0);
    return k;
}
int find_next_min(int x)
{
    int now=root,k=0;
    while (now)
    {
        if (a[now].data<x)
            k=(a[k].data<a[now].data||!k)?now:k,
            now=a[now].right;
        else now=a[now].left;
    }
    if (k) splay(k,0);
    return k;
}
main()
{
    n=in();
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&hand,&x);
        if (!root) flag=hand;
        if (flag==hand) insert(x);
        else
        {
            int p,p1=find_next_min(x),p2=find_next_max(x);
            if (p1&&(x-a[p1].data<=a[p2].data-x||!p2)) p=p1;
            else p=p2;
            ans=(ans+abs(a[p].data-x))%mod;
            del(p);
        }
    }
    printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值