HDU 3726 Graph and Queries splay 离线 模拟

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3726

题意:

给一个无向图,图中有 n(1<=n<=2e4) 个节点, m(1<=m<=6e4) 条边,每个点都有一个权值 v1e6<=v<=1e6 ,三种操作

  • D X 删除编号为X的边 操作次数不超过 2e5
  • Q X K 询问X所在连通块中第K大的点值是多少,如果K非法,答案为0 操作次数不超过 2e5
  • C X V 把编号为X的点的权值变为V 操作次数不超过 1e5

每组样例输出Q操作的平均值

思路:

离线倒过来进行操作,这样删边就成了加边,对应的splay操作就是合并两个splay树,可以把小一点的树加到大一点的树里面,其他的都是普通的splay操作
用到了并查集来合并点,以及邻接表来储存点值的变化

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define MS(x, y) memset(x, y, sizeof(x))
#define lson(x) son[x][0]
#define rson(x) son[x][1]

typedef long long LL;
const int MAXN = 2e4 + 5;

struct Edge{
    int v, nxt;
    Edge(int v = 0, int nxt = -1): v(v), nxt(nxt) {}
};

Edge edge[300005];
int head[MAXN], edgenum;
int pre[MAXN], son[MAXN][2], siz[MAXN], data[MAXN], node[MAXN];
int tot;
int node_val[MAXN], edges[60005][2];
int fa[MAXN];
char str[5];
bool deleted[60005];
int op[500005], pam[500005][2];
int n, m, q;

void addedge(int u, int v) {
    edge[edgenum] = Edge(v, head[u]);
    head[u] = edgenum++;
}

int Find(int x) {
    if (x != fa[x]) fa[x] = Find(fa[x]);
    return fa[x];
}

bool Merge(int x, int y) {
    x = Find(x);
    y = Find(y);
    if (x == y) return false;
    fa[x] = y;
    return true;
}

void pushup(int x) {
    siz[x] = siz[lson(x)] + siz[rson(x)] + 1;
}

int newnode(int val, int fa, int method = -1) {
    int ret;
    if (~method) ret = method;
    else ret = ++tot;
    pre[ret] = fa;
    siz[ret] = 1;
    data[ret] = val;
    MS(son[ret], 0);
    return ret;
}

void init() {
    tot = 0;
    lson(0) = rson(0) = pre[0] = siz[0] = 0;

    for (int i = 1; i <= n; ++i) fa[i] = i;
    MS(deleted, false);

    MS(head, -1);
    edgenum = 0;
}

void Rotate(int x, int kind) {
    int y = pre[x];
    son[y][!kind] = son[x][kind];
    pre[son[x][kind]] = y;
    if (pre[y]) {
        son[pre[y]][son[pre[y]][1] == y] = x;
    }
    pre[x] = pre[y];
    son[x][kind] = y;
    pre[y] = x;
    pushup(y);
}

void splay(int x, int goal) {
    int y, kind;
    while (pre[x] != goal) {
        if (pre[pre[x]] == goal) Rotate(x, son[pre[x]][0] == x);
        else {
            y = pre[x];
            kind = (lson(pre[y]) == y);
            if (son[y][kind] == x) {
                Rotate(x, !kind);
                Rotate(x, kind);
            } else {
                Rotate(y, kind);
                Rotate(x, kind);
            }
        }
    }
    pushup(x);
}

int get_min(int x) {
    while (lson(x)) {
        x = lson(x);
    }
    return x;
}

int get_max(int x) {
    while (rson(x)) {
        x = rson(x);
    }
    return x;
}

int get_kth(int k, int x) {
    int s;
    while (x) {
        s = siz[lson(x)] + 1;
        if (s == k) return x;
        if (s > k) x = lson(x);
        else k -= s, x = rson(x);
    }
}

int deleteroot(int root) {
    if (!lson(root) || !rson(root)) {
        root = lson(root) + rson(root);
        pre[root] = 0;
        return root;
    }
    int k = get_min(rson(root));
    splay(k, root);
    lson(k) = lson(root);
    pre[lson(root)] = k;
    root = k;
    pre[root] = 0;
    pushup(root);
    return root;
}

void Insert(int x, int y) {
    if (data[x] <= data[y]) {
        if (!lson(y)) {
            lson(y) = newnode(data[x], y, x);
        } else {
            Insert(x, lson(y));
        }
    } else {
        if (!rson(y)) {
            rson(y) = newnode(data[x], y, x);
        } else {
            Insert(x, rson(y));
        }
    }
    pushup(y);
}

void dfs(int x, int y) {
    if (!x) return ;
    dfs(lson(x), y);
    dfs(rson(x), y);
    Insert(x, y);
}

void mergeNode(int x, int y) {
    while (pre[x]) x = pre[x];
    while (pre[y]) y = pre[y];
    if (siz[x] > siz[y]) swap(x, y);
    dfs(x, y);
}

void Change(int x, int val) {
    splay(x, 0);
    int root = deleteroot(x);
    data[x] = val;
    if(root) Insert(x, root);
}

int Query(int x, int k) {
    while (pre[x]) x = pre[x];
    if (k <= 0 || k > siz[x]) return 0;
    k = siz[x] + 1 - k;
    return data[get_kth(k, x)];
}

int main() {
    int kase = 0;
    while (~scanf("%d%d", &n, &m)) {
        if (n == 0 || m == 0) break;
        init();

        int x, y, div = 0;
        LL sum = 0;

        for (int i = 1; i <= n; ++i) scanf("%d", node_val + i), addedge(i, node_val[i]);
        for (int i = 1; i <= m; ++i) scanf("%d%d", &edges[i][0], &edges[i][1]);
        for (q = 1; ; ++q) {
            scanf("%s", str);
            if (str[0] == 'E') break;
            scanf("%d", &x);
            pam[q][0] = x;
            if (str[0] == 'D') deleted[x] = true, op[q] = 1;
            else {
                scanf("%d", &y);
                pam[q][1] = y;
                if (str[0] == 'C') addedge(x, y), node_val[x] = y, op[q] = 2;
                else op[q] = 3;
            }
        }

        for (int i = 1; i <= n; ++i) {
            node[i] = newnode(node_val[i], 0);
        }
        for (int i = 1; i <= m; ++i) if (!deleted[i]) {
            if (!Merge(edges[i][0], edges[i][1])) continue;
            mergeNode(node[edges[i][0]], node[edges[i][1]]);
        }
        for (int i = q - 1; i; --i) {
            x = pam[i][0];
            if (op[i] == 1) {
                if (!Merge(edges[x][0], edges[x][1])) continue;
                mergeNode(node[edges[x][0]], node[edges[x][1]]);
            } else if (op[i] == 2) {
                y = head[x];
                Change(node[x], edge[edge[y].nxt].v);
                head[x] = edge[y].nxt;
            } else {
                y = pam[i][1];
                sum += Query(x, y);
                ++div;
            }
        }

        printf("Case %d: %.6f\n", ++kase, 1. * sum / div);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值