给出一片森林,每个点有一个权值,要求支持动态连边,并回答任意两点间第 k 小权值,强制在线。\((1\le N,M,T \le 8\times 10^4)\)
分析
求第 k 小权值,这个肯定是用主席树了,但连边该怎么办?LCT?可我不会。
我们可以用启发式合并的方法,连边也就是合并两棵树,我们每次将较小的树连到较大的树上去,更新信息就暴力 dfs 较小树中的每一个点就好了。
代码
#include <bits/stdc++.h>
#define N 80003
#define DEBUG puts("ok")
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
int gi() {
int x = 0, f = 1; char c = getchar();
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, q, len, tot, num;
int val[N], hs[N];
int fa[N][16], dep[N], sz[N], rt[N];
int to[N << 4], nxt[N << 4], hd[N << 4], ecnt;
int tr[N << 1], L[N << 5], R[N << 5], cnt[N << 5];
bool vis[N];
int get(int k) { return lower_bound(hs + 1, hs + 1 + len, k) - hs; }
void insert(int u, int v) { to[++ecnt] = v, nxt[ecnt] = hd[u], hd[u] = ecnt; }
void modify(int lst, int &now, int l, int r, int k) {
if (!now) now = ++tot;
cnt[now] = cnt[lst] + 1;
if (l == r) return;
int mid = l + r >> 1;
if (k <= mid) R[now] = R[lst], modify(L[lst], L[now], l, mid, k);
else L[now] = L[lst], modify(R[lst], R[now], mid + 1, r, k);
}
void dfs(int u, int f, int root) {
vis[u] = 1, fa[u][0] = f, dep[u] = dep[f] + 1, sz[root]++, rt[u] = root;
modify(tr[f], tr[u], 1, len, get(val[u]));
for (int i = 1; i <= 15; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (int i = hd[u]; i; i = nxt[i]) {
int v = to[i];
if (v == f) continue;
dfs(v, u, root);
}
}
int LCA(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
for (int i = 15; i >= 0; --i)
if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
if (u == v) return u;
for (int i = 15; i >= 0; --i)
if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
int query(int u, int v, int w, int f, int l, int r, int k) {
if (l == r) return l;
int sum, mid = l + r >> 1;
sum = cnt[L[u]] + cnt[L[v]] - cnt[L[w]] - cnt[L[f]];
if (k <= sum) return query(L[u], L[v], L[w], L[f], l, mid, k);
else return query(R[u], R[v], R[w], R[f], mid + 1, r, k - sum);
}
void merge(int u, int v) {
insert(u, v), insert(v, u);
int r1 = rt[u], r2 = rt[v];
if (sz[r1] > sz[r2]) dfs(v, u, r1);
else dfs(u, v, r2);
}
int main() {
int T = gi();
int u, v, k, lst = 0; char ch[2];
n = gi(), m = gi(), q = gi();
for (int i = 1; i <= n; ++i) val[i] = hs[i] = gi();
sort(hs + 1, hs + 1 + n);
len = unique(hs + 1, hs + 1 + n) - hs - 1;
for (int i = 1; i <= m; ++i) {
u = gi(), v = gi();
insert(u, v), insert(v, u);
}
for (int i = 1; i <= n; ++i) if (!vis[i]) dfs(i, 0, i);
for (int i = 1; i <= q; ++i) {
scanf("%s", ch);
u = gi() ^ lst, v = gi() ^ lst;
if (ch[0] == 'Q') {
k = gi() ^ lst;
int w = LCA(u, v), f = fa[w][0];
printf("%d\n", lst = hs[query(tr[u], tr[v], tr[w], tr[f], 1, len, k)]);
}
else merge(u, v);
}
return 0;
}
原文地址:https://www.cnblogs.com/hlw1/p/12266181.html
时间: 2024-10-29 02:33:53