HDU 5096 ACM Rank Treap综合

来源:互联网 发布:龙腾世纪起源优化 编辑:程序博客网 时间:2024/04/25 21:34

题目链接

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

法二:树状数组

等等补