BZOJ 1208: [HNOI2004]宠物收养所 (Splaytree)

本文介绍使用SplayTree实现插入、删除节点等操作,并详细解释了如何求解第k大的数及小于某值的个数等问题。代码示例中包含了旋转、调整平衡等关键步骤。

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

用Splaytree实现插入一个节点,删除一个节点,求第k大的数,求小于某值的个数,还是挺好玩的,注意这题答案要mod一下。


#include 
#include 
using namespace std;
typedef long long ll;
  
const int maxn = 80000 + 10;
const int mod = 1000000;
const int inf = 2e9;
  
#define lson x->ch[0]
#define rson x->ch[1]
#define ket (root->ch[1]->ch[0])
  
struct NODE {
    NODE *pre, *ch[2];
    int val, id, sz;
  
    void up() {
        sz = ch[0]->sz + ch[1]->sz + 1;
    }
};
  
struct Splaytree {
    NODE node[maxn], *null, *root;
    int top;
  
    void Rotate(NODE *x, int c) {
        NODE *y = x->pre;
        y->ch[!c] = x->ch[c];
        if(x->ch[c] != null) x->ch[c]->pre = y;
        x->pre = y->pre;
        if(y->pre != null)  y->pre->ch[ y->pre->ch[1]==y ] = x;
        x->ch[c] = y; y->pre = x;
        y->up();
    }
  
    void Splay(NODE *x, NODE *go) {
        while(x->pre != go) {
            if(x->pre->pre == go)   Rotate(x, x->pre->ch[0] == x);
            else {
                NODE *y = x->pre, *z = y->pre;
                int f = z->ch[1] == y;
                if(y->ch[f] == x)   Rotate(y, !f);
                else    Rotate(x, f);
                Rotate(x, !f);
            }
        }
        x->up();
        if(go == null)  root = x;
    }
  
    void RTO(int k, NODE *go) {
        NODE *x = root;
        while(lson->sz != k) {
            if(lson->sz > k)    x = lson;
            else {
                k -= lson->sz + 1;
                x = rson;
            }
        }
        Splay(x, go);
    }
  
    void debug(NODE *x) {
        if(x != null) {
            printf("节点: %2d  左儿子: %2d 右儿子: %2d size = %2d val = %2d\n",
                x->id, x->ch[0]->id, x->ch[1]->id, x->sz, x->val);
            debug(x->ch[0]);
            debug(x->ch[1]);
        }
    }
  
    int find_kth(NODE*x, int k) {
        if(lson->sz == k)   return x->val;
        if(lson->sz > k)    return find_kth(lson, k);
        return find_kth(rson, k - lson->sz - 1);
    }
  
    int find_sm(NODE* x, int c) {
        if(x == null)   return 0;
        if(x->val <= c) return lson->sz + 1 + find_sm(rson, c);
        else    return find_sm(lson, c);
    }
  
    void Delete(int l, int r) {
        RTO(l-1, null);
        RTO(r+1, root);
        ket = null;
        root->ch[1]->up(); root->up();
    }
  
    void Insert(int c) {
        NODE *x = root;
        if(x == null) {
            x = newnode(c, null);
            root = x;
            return ;
        }
        while(x->ch[x->val < c] != null)
            x = x->ch[x->val < c];
        x->ch[x->val < c] = newnode(c, x);
        Splay(x->ch[x->val < c], null);
    }
  
    NODE* newnode(int c, NODE *f) {
        NODE *x = &node[++top];
        x->val = c; x->sz = 1; x->id = top;
        lson = rson = null;
        x->pre = f;
        return x;
    }
  
    void init() {
        null = &node[0];
        null->sz = null->id = null->val = 0;
        top = 0;
        root = null;
        Insert(-inf); Insert(inf);
    }
  
    int gao(int b) {
        int cnt = find_sm(root, b);
        int c1 = find_kth(root, cnt-1), c2 = find_kth(root, cnt);
        if((ll)b - c1 <= (ll)c2 - b){
            Delete(cnt-1, cnt-1);
            return b-c1;
        }
        else {
            Delete(cnt, cnt);
            return c2-b;
        }
    }
}*Q, *L;
  
void solve() {
    Q = new Splaytree; L = new Splaytree;
    Q->init(); L->init();
    int n, a, b;
    scanf("%d", &n);
    int ans = 0;
    while(n--) {
        scanf("%d%d", &a, &b);
        if(!a) {
            if(L->root->sz > 2)
                ans += L->gao(b);
            else
                Q->Insert(b);
        }
        else {
            if(Q->root->sz > 2)
                ans += Q->gao(b);
            else
                L->Insert(b);
        }
        ans %= mod;
    }
    printf("%d\n", ans);
}
  
int main() {
    solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值