题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3726
题意:
给一个无向图,图中有 n(1<=n<=2e4) 个节点, m(1<=m<=6e4) 条边,每个点都有一个权值 v(−1e6<=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);
}
}