[HNOI2004, 洛谷P2286]寵物收容所

題目描述

凡凡開了一間寵物收養場。收養場提供兩種服務:收養被主人遺棄的寵物和讓新的主人領養這些寵物。

每個領養者都希望領養到自己滿意的寵物,凡凡根據領養者的要求通過他自己發明的一個特殊的公式,得出該領養者希望領養的寵物的特點值a(a是一個正整數,a<2^31),而他也給每個處在收養場的寵物一個特點值。這樣他就能夠很方便的處理整個領養寵物的過程了,寵物收養場總是會有兩種情況發生:被遺棄的寵物過多或者是想要收養寵物的人太多,而寵物太少。

被遺棄的寵物過多時,假若到來一個領養者,這個領養者希望領養的寵物的特點值爲a,那麼它將會領養一隻目前未被領養的寵物中特點值最接近a的一隻寵物。(任何兩隻寵物的特點值都不可能是相同的,任何兩個領養者的希望領養寵物的特點值也不可能是一樣的)如果有兩隻滿足要求的寵物,即存在兩隻寵物他們的特點值分別爲a-b和a+b,那麼領養者將會領養特點值爲a-b的那隻寵物。

收養寵物的人過多,假若到來一隻被收養的寵物,那麼哪個領養者能夠領養它呢?能夠領養它的領養者,是那個希望被領養寵物的特點值最接近該寵物特點值的領養者,如果該寵物的特點值爲a,存在兩個領養者他們希望領養寵物的特點值分別爲a-b和a+b,那麼特點值爲a-b的那個領養者將成功領養該寵物。

一個領養者領養了一個特點值爲a的寵物,而它本身希望領養的寵物的特點值爲b,那麼這個領養者的不滿意程度爲abs(a-b)。

你得到了一年當中,領養者和被收養寵物到來收養所的情況,請你計算所有收養了寵物的領養者的不滿意程度的總和。這一年初始時,收養所裏面既沒有寵物,也沒有領養者。

輸入輸出格式

輸入格式:
第一行爲一個正整數n,n<=80000,表示一年當中來到收養場的寵物和領養者的總數。接下來的n行,按到來時間的先後順序描述了一年當中來到收養場的寵物和領養者的情況。每行有兩個正整數a, b,其中a=0表示寵物,a=1表示領養者,b表示寵物的特點值或是領養者希望領養寵物的特點值。(同一時間呆在收養所中的,要麼全是寵物,要麼全是領養者,這些寵物和領養者的個數不會超過10000個)

輸出格式:
僅有一個正整數,表示一年當中所有收養了寵物的領養者的不滿意程度的總和mod 1000000以後的結果。

思路還是很好想的, 寵物隊列和收養者隊列必定一者爲空或同時爲空. 我用了無旋Treap, 寫了一小時, 寫出了這種這樣bug… 調了一個多小時才調好
比如, getMin(), getMax()函數中的while寫成了if.
一些函數沒有傳引用, 一部分邏輯bug.

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
const int MOD = 1e6;
struct Treap{
    Treap * left, * right;
    int value, priority, size;
    Treap(){};
    Treap(Treap * l, Treap * r, int v, int p): left(l), right(r), value(v), priority(p){
        size = 1;
    }
    void maintain(){
        size = left->size + right->size + 1;
    }
    int getSize(){
        return size - 2;// 哨兵有兩個
    }
};
Treap * null = new Treap(), * pet = null, * person = null;
typedef pair<Treap *, Treap *> pTT;
pTT split_l(Treap * o, int val){
    if(o == null){
        return make_pair(null, null);
    }
    pTT result;
    if(o->value <= val){
        result = split_l(o->right, val);
        o->right = result.first;
        o->maintain();
        result.first = o;
    }
    else{
        result = split_l(o->left, val);
        o->left = result.second;
        o->maintain();
        result.second = o;
    }
    return result;
}
pTT split_r(Treap * o, int val){
    if(o == null){
        return make_pair(null, null);
    }
    pTT result;
    if(o->value < val){
        result = split_r(o->right, val);
        o->right = result.first;
        o->maintain();
        result.first = o;
    }
    else{
        result = split_r(o->left, val);
        o->left = result.second;
        o->maintain();
        result.second = o;
    }
    return result;
}
Treap * merge(Treap * left, Treap * right){
    if(left == null){
        return right;
    }
    if(right == null){
        return left;
    }
    if(left->priority < right->priority){
        left->right = merge(left->right, right);
        left->maintain();
        return left;
    }
    else{
        right->left = merge(left, right->left);
        right->maintain();
        return right;
    }
}
int getMax(Treap * root){
    while(root->right != null){// while 寫成 if...
        root = root->right;
    }
    return root->value;
}
int getMin(Treap * root){// 只查詢的函數, 不需要引用
    while(root->left != null){
        root = root->left;
    }
    return root->value;
}
int getNext(Treap * & root, int val){
    pTT tree = split_l(root, val);
    int rst = getMin(tree.second);
    root = merge(tree.first, tree.second);
    return rst;
}
int getPre(Treap * & root, int val){
    pTT tree = split_r(root, val);// 這裏的邏輯要注意, 先分那個, 再分那個
    pTT right = split_l(tree.second, val);
    if(right.first != null){
        root = merge(tree.first, merge(right.first, right.second));
        return val;
    }
    tree.second = merge(right.first, right.second);

    int rst = getMax(tree.first);
    root = merge(tree.first, tree.second);
    return rst;
}
void insert(Treap * & root, int val){// 這種帶修改的函數, 要傳引用
    pTT tree = split_l(root, val);
    Treap * t = new Treap(null, null, val, rand());
    root = merge(merge(tree.first, t), tree.second);
}
void remove(Treap * & root, int val){
    pTT tree = split_l(root, val);
    pTT left = split_r(tree.first, val);

    left.second = merge(left.second->left, left.second->right);
    root = merge(merge(left.first, left.second), tree.second);
}
int main(){
    int inf = 0x3f3f3f3f;
    null->size = 0;

    int n, opt, a;
    long long cnt = 0;
    scanf("%d", &n);
    insert(pet, inf), insert(pet, -inf);// 哨兵方便計算
    insert(person, inf), insert(person, -inf);

    while(n--){
        scanf("%d%d", &opt, &a);
        if(opt){
            if(pet->getSize()){
                int pre = getPre(pet, a);
                int suc = getNext(pet, a);
                if(suc - a < a - pre){
                    remove(pet, suc);
                    cnt += suc - a;
                }
                else{
                    remove(pet, pre);
                    cnt += a - pre;
                }
                cnt %= MOD;
            }
            else{
                insert(person, a);
            }
        }
        else{
            if(person->getSize()){
                int pre = getPre(person, a);
                int suc = getNext(person, a);
                if(suc - a < a - pre){
                    remove(person, suc);
                    cnt += suc - a;
                }
                else{
                    remove(person, pre);
                    cnt += a - pre;
                }
                cnt %= MOD;
            }
            else{
                insert(pet, a);
            }
        }
    }
    printf("%lld\n", cnt);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章