HDU 5096 ACM Rank Treap綜合

題目鏈接

2017.9.5 1:40
用很大很大的數據量對拍了好久好久終於找出了錯誤
智障到哭泣
erase
bool dir = t->ch[1]->key < t->ch[0]->key;
寫成了 bool dir = t->ch[1]->val < t->ch[0]->val;
一直RE完全不知道哪裏出了問題,只好一點一點跟別人的代碼對,很多無關緊要的地方都改成了別人寫的樣子(...)就很心累。做數據結構的題有沒有必要呢......反正比賽時也不會寫,會寫也來不及寫,寫完也來不及調,更何況還每次都有智障錯誤,
而且還開學了
深夜低氣壓,先扔一發代碼明天再完善博文了...。

題意

若干組submission 與詢問,問當前恰好第 k 名是哪支隊伍,以及第 k 支隊伍的名次。
排名的依據是1. 過題數;2. penalty ;3. 最後過的一題的編號
前兩個指標都一樣的話排名就相同,對於相同排名的在輸出的時候輸出其中第三個指標最優的。

法一:Treap

思路

treap 維護。顯然,過題數與 penalty 可以扔到一個結構體裏面,就相當於 treapval 值。
爲什麼不把最後過的一題的編號也加進去呢?注意到,題目要詢問恰好第 k 名是哪支隊伍(有並列的情況),如果一個隊伍一個節點的話處理起來就很麻煩。而一個排名一個節點的話就很好處理了,每個節點上再記個 cnt 即可。
那麼最後怎麼輸出第三個指標最優的呢?參考了 hdu 5096 ACM Rank(treap) ——yamiedie_,在節點裏面再開一個 set .
問第 k 名是哪個隊伍是常規的 treap 應用,那麼問第 k 支隊伍的名次呢,按其 val 值進去查找即可。

Code

#include <bits/stdc++.h>
#define maxn 20010
using namespace std;
int cnt[maxn], trial[maxn][12], last[maxn], pen[maxn], lstacc[maxn];
bool solve[maxn][12];
char s[100];
struct Sta {
    int cnt, pen;
    Sta(int _cnt=0, int _pen=0) : cnt(_cnt), pen(_pen) {}
    bool operator < (const Sta& sta) const {
        return cnt > sta.cnt || (cnt == sta.cnt && pen < sta.pen);
    }
    bool operator == (const Sta& sta) const {
        return cnt == sta.cnt && pen == sta.pen;
    }
};
struct cmp {
    bool operator()(const int &a, const int &b) const{
        return lstacc[a] < lstacc[b] || (lstacc[a] == lstacc[b] && a < b);
    }
};
struct node {
    Sta val; int key, sz, cnt;
    node* ch[2];
    set<int, cmp> s;
    node() { sz = 0, key = INT_MAX, s.clear(); }
    node(Sta sta, int id);
    update() { sz = ch[0]->sz + ch[1]->sz + cnt; }
}* null = new node;
node::node(Sta sta, int id) {
    val = sta, key = rand(), sz = cnt = 1;
    ch[0] = ch[1] = null;
    s.clear(); s.insert(id);
}
struct Treap {
    node* root;
    Treap() { root = null; }
    void rotate(node*& t, bool d) {
        node* p = t->ch[d];
        t->ch[d] = p->ch[!d];
        p->ch[!d] = t;
        t->update(), p->update();
        t = p;
    }
    void insert(node*& t, Sta sta, int id) {
        if (t == null) { t = new node(sta, id); return; }
        if (t->val == sta) {
            ++t->cnt, t->s.insert(id);
            t->update();
            return;
        }
        bool dir = !(sta < t->val);
        insert(t->ch[dir], sta, id);
        if (t->ch[dir]->key < t->key) rotate(t, dir);
        else t->update();
    }
    void erase(node*& t, Sta sta, int id) {
        if (t == null) return;
        if (t->val == sta) {
            if (t->cnt > 1) {
                --t->cnt; t->s.erase(id);
                t->update();
                return;
            }
            bool dir = t->ch[1]->key < t->ch[0]->key;
            if (t->ch[dir] == null) { delete t; t = null; return; }
            if (t->ch[!dir] == null) { node* p = t->ch[dir]; delete t; t = p; return; }
            rotate(t, dir);
            erase(t->ch[!dir], sta, id);
            t->update();
            return;
        }
        bool dir = !(sta < t->val);
        erase(t->ch[dir], sta, id);
        t->update();
    }
    void insert(Sta sta, int id) {
        insert(root, sta, id);
    }
    void erase(Sta sta, int id) {
        erase(root, sta, id);
    }
    int calckth(int k) {
        if (k <= 0 || k > root->sz) return -1;
        bool dir;
        for (node* t = root; t != null; t = t->ch[dir]) {
            int num = t->ch[0]->sz;
            if (k == num+1) return *(t->s.begin());
            else if (k <= num) dir = 0;
            else {
                k -= (num + t->cnt);
                if (k <= 0) return -1;
                else dir = 1;
            }
        }
    }
    int find(node*& t, Sta sta) {
        if (t->val == sta) return t->ch[0]->sz + 1;
        bool d = !(sta < t->val);
        if (d == 0) return find(t->ch[d], sta);
        else return t->ch[0]->sz + t->cnt + find(t->ch[d], sta);
    }
    void clear(node*& t) {
        if (t->ch[0] != null) clear(t->ch[0]);
        if (t->ch[1] != null) clear(t->ch[1]);
        delete t; t = null;
    }
    void clear() { clear(root); }
    int find(Sta sta) { return find(root, sta); }
    int size() { return root->sz; }
}* treap = new Treap;
int readint() {
    char c;
    while((c = getchar()) && !(c >= '0' && c <= '9'));
    int ret = c - '0';
    while((c = getchar()) && c >= '0' && c <= '9')
        ret = ret * 10 + c - '0';
    return ret;
}
char readc() {
    char c;
    while((c = getchar()) && !isalpha(c));
    return c;
}
int n, m, kas;
void work() {
    memset(cnt, 0, sizeof(cnt));
    memset(pen, 0, sizeof(pen));
    memset(solve, 0, sizeof(solve));
    memset(last, -1, sizeof(last));
    memset(trial, 0, sizeof(trial));
    memset(lstacc, 0, sizeof(lstacc));
    if (treap->root != null) treap->clear();

    for (int i = 0; i < n; ++i) treap->insert(Sta(0, 0), i);
    char op[20];
    int order = 0;

    while (scanf("%s", op) && op[0] != 'C') {
        ++order;
        int k, x;
        if (op[0] == 'S') {
            int time = readint(), team = readint(), prob = readc()-'A', stat = readint();
            if (!solve[team][prob] && (last[team] == -1 || time - last[team] >= 5)) {
                if (stat != 1) { last[team] = time; ++trial[team][prob]; continue; }
                Sta sta1(cnt[team], pen[team]);
                treap->erase(sta1, team);
                solve[team][prob] = true, ++cnt[team];
                pen[team] += time + trial[team][prob] * 20;
                last[team] = time;
                lstacc[team] = order;
                Sta sta2(cnt[team], pen[team]);
                treap->insert(sta2, team);
                printf("[%d][%c]\n", team, prob+'A');
            }
        }
        else if (op[0] == 'T') {
            scanf("%d", &k);
            printf("%d\n", treap->calckth(k));
        }
        else if (op[0] == 'R') {
            scanf("%d", &x);
            Sta sta(cnt[x], pen[x]);
            printf("%d\n", treap->find(sta));
        }
    }
    scanf("%s", op);
    printf("\n");
}
int main() {
    while (scanf("%d%d", &n, &m) != EOF) work();
    return 0;
}

問題

  1. 多組數據最好要回收內存,寫在了 clear() 裏面
  2. 這道題的讀入一開始也出了點問題 0 0
  3. 輸出時每組數據之間要空行
  4. 應將 last[] 初始化爲 1 ,否則判斷是否相隔五分鐘的時候會出問題(…)
  5. 第三個排序的指標不是最後一次提交的時間,而是反應在 submissionlist 上的順序…
  6. erase
    bool dir = t->ch[1]->key < t->ch[0]->key;
    寫成了 bool dir = t->ch[1]->val < t->ch[0]->val;這貌似還不是第一次…。

法二:樹狀數組

等等補

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章