hdu 5096 ACM Rank(treap)

模拟一个acm比赛的排名, 并且支持询问排在第k个的是哪个队和第i个队排第几


丧心病狂, 第一次见1W个队的ACM。


看起来是平衡树, 不过好多细节。。。



首先对于每个提交, 先判断是不是有效的,如果是有效的话就看是不是ac, 如果不是ac的话对应队伍的对应题目要加罚时, 如果ac了的话对应队伍的总时间要加上用时t和对应题目的罚时, 然后做的题目要加1, 这里为了方便就不是题目加1, 而是把总用时减去一个很大的数(1e7),然后在treap里面排的时候就是按照总时间来排, 然后ac了的话要更新最后提交时间和最后ac时间, 没有ac的话就要更新最后提交时间, 比较蛋疼的就是罚时相等的时候, 要按照它说的规则, 于是就在treap的节点里面加个set, 然后搞一下仿函数。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <string>
#include <set>
#include <cstdlib>
#include <algorithm>
using namespace std;

#define mnx 20002
#define N 3020
#define E 1000200
#define inf 0x3f3f3f3f
#define ls (p[i].ch[0])
#define rs (p[i].ch[1])
#define md ((ll + rr) >> 1)
const int M = 10000000;



bool acc[mnx][11];
int pen[mnx][11]; // 未提交时候的罚时
int lst[mnx];
int cnt[mnx]; // 总罚时
int lstacc[mnx];

int n, k;

struct ff {
    bool operator()(const int &a, const int &b) const{
        if(lstacc[a] == -1 && lstacc[b] == -1) return a < b;
        if(lstacc[a] == -1 || lstacc[b] == -1) return lstacc[b] == -1;
        return lstacc[a] < lstacc[b];
    }
};
struct node {
    int ch[2], r, s, v, cnt;
    set<int, ff> vv;
    node() {}
    void setIt(int v, int id) {
        this -> v = v;
        vv.clear();
        vv.insert(id);
        ch[0] = ch[1] = 0, r = rand(), s = 1;
        cnt = 1;
    }
}p[mnx * 22];
int sz;
int creat(int v, int id) {
    ++ sz;
    p[sz].setIt(v, id);
    return sz;
}
int cmp(int i, int v) {
    if(p[i].v == v) return -1;
    return v < p[i].v? 0: 1;
}
void mt(int i) {
    p[i].s = p[i].cnt;
    if(ls) p[i].s += p[ls].s;
    if(rs) p[i].s += p[rs].s;
}
void rt(int &i, int d) {
    int k = p[i].ch[d^1];
    p[i].ch[d^1] = p[k].ch[d];
    p[k].ch[d] = i;
    mt(i), mt(k);
    i = k;
}
void ins(int &i, int id, int v) {
    if(!i) {
        i = creat(v, id);
        return;
    }
    int d = cmp(i, v);
    if(d == -1) {
        p[i].cnt ++, p[i].s++;
        p[i].vv.insert(id);
        return;
    }
    ins(p[i].ch[d], id, v);
    if(p[p[i].ch[d]].r > p[i].r)
        rt(i, d ^ 1);
    mt(i);
}
set<int, ff>::iterator it;
void Remove(int &i, int id, int v) {
    int d = cmp(i, v);
    if(d == -1) {
        if(p[i].cnt > 1) {
            p[i].cnt--, p[i].s--;
            p[i].vv.erase(id);
            return;
        }
        if(!ls) i = rs;
        else if(!rs) i = ls;
        else {
            int d2 = p[ls].r > p[rs].r? 1: 0;
            rt(i, d2);
            Remove(p[i].ch[d2], id, v);
        }
    }
    else Remove(p[i].ch[d], id, v);
    if(i) mt(i);
}
int kth(int i, int k) {
    if(!i) return -1;
    int d = k - p[ls].s;
    if(d <= 0) return kth(ls, k);
    if(d <= p[i].cnt) {
        if(d != 1) return -1;
        return *(p[i].vv.begin());
    }
    return kth(rs, d - p[i].cnt);
}
int ran(int i, int id, int v) {
    int d = cmp(i, v);
    int c = 0;
    if(ls) c += p[ls].s;
    if(d == -1) return c + 1;
    if(d == 0) return ran(ls, id, v);
    return c + p[i].cnt + ran(rs, id, v);
}
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 main() {
    while(scanf("%d%d", &n, &k) != EOF) {
        int kk = 0;
        memset(pen, 0, sizeof pen);
        memset(lst, -1, sizeof lst);
        memset(cnt, 0, sizeof cnt);
        memset(acc, 0, sizeof acc);
        memset(lstacc, -1, sizeof lstacc);
        int root = 0;
        char op[20];
        sz = 0;
        for(int i = 0; i < n; ++i) {
            ins(root, i, 0);
        }
        while(scanf("%s", op) && op[0] != 'C') {
            ++kk;
            if(op[0] == 'S') {
                int t, team, res;
                int id;
                t = readint();
                team = readint();
                id = readc() - 'A';
                res = readint();
                if(lst[team] != -1 && t - lst[team] < 5) continue;
                if(acc[team][id]) continue;
                if(res == 0) {
                    pen[team][id] += 20;
                    lst[team] = t;
                    continue;
                }
                printf("[%d][%c]\n", team, (char)id + 'A');
                Remove(root, team, cnt[team]);
                cnt[team] += pen[team][id];
                cnt[team] += t;
                acc[team][id] = 1;
                cnt[team] -= M;
                lst[team] = t;
                lstacc[team] = kk;
                ins(root, team, cnt[team]);
                continue;
            }
            int team;
            if(op[0] == 'R') {
                scanf("%d", &team);
                printf("%d\n", ran(root, team, cnt[team]));
                continue;
            }
            int k;
            scanf("%d", &k);
            printf("%d\n", kth(root, k));
        }
        scanf("%s", op);
        puts("");
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值