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;这貌似还不是第一次…。

法二:树状数组

等等补

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