HDU 3726 Graph and Queries (Treap)

来源:互联网 发布:直饮水 知乎 编辑:程序博客网 时间:2024/05/17 03:16

 题意: 给出一幅无向图,点有权,要求支持:

1,删边

2,询问与点u相连的第k大点的权值 (注意k可能不合法)

3,修改一个点权

输出操作2中的权值总和除以操作2的数量。

解法: 离线,用Treap维护第k大,把所有操作倒过来做,那么删边就变成合并两棵树,把点少的树暴力往点多的树里插就可以了。注意修改点权操作,在离线前需要先与原值交换。

/* Created Time: 2013年09月20日 星期五 06时16分58秒 */#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;const int MAXN = 100010;const int INF = 0x3f3f3f3f;int n,m,q,cn;struct Cmd {    char op;    int a,b;    Cmd(char _op = 0, int _a = 0, int _b = 0) :        op(_op), a(_a), b(_b) {}}cmd[MAXN*5];int pre[MAXN];struct Edge {    int u,v,ban;}g[MAXN];struct Node {    Node *ch[2];    int v,size,r;    int cmp(int x) { return x > v; }}*nill, *root[MAXN], *list, memo[MAXN];int ran() {    static int ranx = 123456789;    return ranx += (ranx << 2) + 1; }void up(Node *o) {    o->size = 1;    for (int i = 0; i < 2; i ++)        o->size += o->ch[i]->size;}void New_node(Node *&o, int v) {    o = list; list = o->ch[1];    o->ch[0] = o->ch[1] = nill;    o->v = v; o->size = 1; o->r = ran();}void reuse(Node *o) {    o->ch[1] = list; list = o;}void rotato(Node *&o, int d) {    Node *temp = o; o = o->ch[d^1]; temp->ch[d^1] = o->ch[d];    o->ch[d] = temp; up(o->ch[d]); up(o);}void insert(Node *&o, int val) {    if (o == nill) {        New_node(o,val); return ;    }    int d = o->cmp(val);    insert(o->ch[d],val); up(o);    if (o->ch[d]->r > o->r) rotato(o,d^1);}void remove(Node *&o, int val) {    if (o->v == val) {        if (o->ch[0] == nill || o->ch[1] == nill) {            Node *temp = o;            o = (o->ch[0] == nill) ?                 o->ch[1] : o->ch[0];            reuse(temp);        } else {            if (o->ch[0]->r > o->ch[1]->r)                 rotato(o,1), remove(o->ch[1],val);            else rotato(o,0), remove(o->ch[0],val);            up(o);        }    } else {        int d = o->cmp(val);        remove(o->ch[d],val); up(o);    }}int query(Node *o, int k) {    if (o->ch[1]->size == k-1)         return o->v;    if (o->ch[1]->size >= k)        return query(o->ch[1],k);    return query(o->ch[0], k - o->ch[1]->size - 1);}int fa[MAXN];int Find(int x) {    return fa[x] = (fa[x] == x ? x : Find(fa[x]));}void brute_insert(Node *&to, Node *&o) {    if (o == nill) return ;    brute_insert(to, o->ch[0]);    brute_insert(to, o->ch[1]);    insert(to,o->v);    reuse(o);    o = nill;}void transfer(int i) {    int a = Find(g[i].u),         b = Find(g[i].v);    if (a == b) return ;    if (root[a]->size < root[b]->size) swap(a,b);    fa[b] = a;    brute_insert(root[a], root[b]);}void work() {    for (int i = 1; i <= n; i ++) fa[i] = i;    for (int i = 1; i <= m; i ++)         if (!g[i].ban) transfer(i);    double ans = 0;    int cnt = 0;    for (int i = cn-1; i >= 0; i --) {        if (cmd[i].op == 'D')            transfer(cmd[i].a);        else if (cmd[i].op == 'Q') {            int u = Find(cmd[i].a); cnt ++;            if (cmd[i].b > root[u]->size || cmd[i].b <= 0)                 continue;            ans += (double) query(root[u],cmd[i].b);        } else {            int u = Find(cmd[i].a);            remove(root[u],pre[cmd[i].a]);            insert(root[u],cmd[i].b);            pre[cmd[i].a] = cmd[i].b;        }    }    if (cnt == 0) cnt ++;    printf("%.6lf\n", ans / cnt);}int main() {    int ca = 0;    while (~scanf("%d%d", &n, &m), n || m) {        list = NULL;        for (int i = 0; i < n+10; i ++) {            memo[i].ch[1] = list;            list = memo + i;        }        New_node(nill,0); nill->size = 0;        for (int i = 1; i <= n; i ++) {            root[i] = nill;            scanf("%d", &pre[i]);            insert(root[i],pre[i]);         }        for (int i = 1; i <= m; i ++) {            scanf("%d%d", &g[i].u, &g[i].v);            g[i].ban = 0;        }        char s[2];        cn = 0;        while (~scanf("%s", s), s[0] != 'E') {            int a = 0, b = 0;            if (s[0] == 'D') {                scanf("%d", &a);                g[a].ban = 1;            } else if (s[0] == 'Q') {                scanf("%d%d", &a, &b);            } else {                scanf("%d%d", &a, &b);                remove(root[a], pre[a]);                insert(root[a], b);                swap(pre[a], b);            }            cmd[cn++] = Cmd(s[0],a,b);        }        printf("Case %d: ", ++ca);        work();    }    return 0;}