1. 程式人生 > >8.Bzoj1208: [HNOI2004]寵物收養所 (Treap)

8.Bzoj1208: [HNOI2004]寵物收養所 (Treap)

Bzoj1208: [HNOI2004]寵物收養所 (Treap)

這個題要求求前驅和後繼,然後對寵物造一顆樹,對人造一顆樹.
程式碼不難寫,題意比較難懂.
當新來一隻寵物時,如果此時沒有人,人樹為空時.那麼這隻寵物就暫時存下來,如果有人,那麼久領養.
同理,人也是這樣.

#include <iostream>
#include <cstdio>
#include <algorithm>
#define rep(i , x, p) for(int i = x;i <= p;++ i)
#define sep(i , x, p) for(int i = x;i >= p;-- i)
#define gc getchar()
#define pc putchar
using namespace std;
const int inf = 1e9;
const int maxN = 100000 + 7;
const int mod = 1000000;

inline int read() {int x = 0,f = 1;char c = gc;while(c < '0' || c > '9') {if(c == '-')f = -1;c = gc;}while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = gc;}return x * f;}
void print(int x) {if(x < 0) pc('-') , x = -x;if(x >= 10) print(x / 10);pc(x % 10 + '0');}

struct Node {
    int ch[maxN][2] , pos[maxN], size[maxN], key[maxN], rt, cnt;
    void up(int i) {size[i] = size[ch[i][0]] + size[ch[i][1]] + 1;return ;}
    void spin(int &i , int p) {
        int tmp = ch[i][p];
        ch[i][p] = ch[tmp][!p];ch[tmp][!p] = i;up(i);i = tmp;up(i);
    }
    
    void Insert(int &i , int x) {
        if(!i) {
            ++ cnt;i = cnt;
            size[i] = 1;pos[i] = rand();
            key[i] = x;
            return ;
        }
        if(key[i] >= x) {
            Insert(ch[i][0] , x);
            if(pos[i] < pos[ch[i][0]]) spin(i , 0);
        }
        else {
            Insert(ch[i][1] , x);
            if(pos[i] < pos[ch[i][1]]) spin(i , 1);
        }
        up(i);
    }
    
    int pre(int i , int x) {
        if(!i) return -inf;
        if(key[i] < x) return max(pre(ch[i][1] , x) , key[i]);
        return pre(ch[i][0] , x);
    }
    
    int nxt(int i , int x) {
        if(!i) return inf;
        if(key[i] > x) return min(nxt(ch[i][0] , x) , key[i]);
        return nxt(ch[i][1] , x);
    }
    
    void Dele(int &i , int x) {
        if(key[i] == x) {
            if(ch[i][0] * ch[i][1] == 0) {i = ch[i][0] + ch[i][1];return ;}
            if(pos[ch[i][0]] > pos[ch[i][1]]) {spin(i , 1); Dele(ch[i][0] , x);}
            else {spin(i , 0) , Dele(ch[i][1] , x);} 
        }else {
            if(x < key[i]) Dele(ch[i][0] , x);  
            else Dele(ch[i][1] , x);
        }
        up(i);
    }
}f1 , f2;
int ans;

void work1(int x) {
    int q1 = f1.pre(f1.rt , x) , q2 = f1.nxt(f1.rt , x) , tmp;
    if(q1 == -inf) {tmp = q2 - x , f1.Dele(f1.rt , q2);}
    else if(q2 == inf) {tmp = x - q1 , f1.Dele(f1.rt , q1);}
    else if(abs(q1 - x) <= abs(q2 - x) ) {f1.Dele(f1.rt , q1);tmp = x - q1;}
    else {f1.Dele(f1.rt , q2);tmp = q2 - x;}
    ans = (ans + tmp) % mod ;
}

void work2(int x) {
    int q1 = f2.pre(f2.rt , x) , q2 = f2.nxt(f2.rt , x) , tmp;
    if(q1 == -inf) {tmp = q2 - x , f2.Dele(f2.rt , q2);}
    else if(q2 == inf) {tmp = x - q1 , f2.Dele(f2.rt , q1);}
    else if(x - q1 <= q2 - x) {f2.Dele(f2.rt , q1);tmp = x - q1;}
    else {f2.Dele(f2.rt , q2);tmp = q2 - x;}
    ans = (ans + tmp) % mod ;
}

int main() {
    int n = read() , opt, x, l1 = 0, l2 = 0;
    rep(i , 1, n) {
        opt = read();x = read();
        if(opt == 0) {l1 ++;if(l2) work2(x), l1 -- ,l2 --;else f1.Insert(f1.rt , x);}
        else {l2 ++;if(l1) work1(x) , l1 -- ,l2 --;else f2.Insert(f2.rt , x);}
    }
    print(ans);
    return 0;
}

考察點

對題意的理解 與 程式碼封裝的考驗