Luogu3302 [SDOI2013]森林
Posted xunzhen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu3302 [SDOI2013]森林相关的知识,希望对你有一定的参考价值。
Description
给你一个森林,你需要支持两个操作:
查询一条路径上第(k)小的权值是多少
连接两个点
强制在线
Solution
我们一开始看到这道题,一定会想什么LCT套主席树 乱编的
其实我们只需要主席树就可以了。我们发现这题只需要连边,不需要断边。所以我们可以启发式合并,暴力维护较小的那部分的主席树和倍增数组
时间复杂度(mathcal{O}(n log^2 n))
如果你还不会用主席树维护链上第(k)大,请右转 传送门
Solution
#include <bits/stdc++.h>
using namespace std;
#define fst first
#define snd second
#define mp make_pair
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef pair<int, int> pii;
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
inline int read() {
int sum = 0, fg = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == ‘-‘) fg = -1;
for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
return fg * sum;
}
const int maxn = 8e4 + 10;
int n, m, q, len;
int w[maxn], t[maxn];
vector<int> g[maxn];
int Fa[maxn], sz[maxn];
inline int find(int x) { return x == Fa[x] ? x : Fa[x] = find(Fa[x]); }
inline void merge(int x, int y) { x = find(x), y = find(y), Fa[x] = y, sz[y] += x; }
int rt[maxn];
namespace ST {
int cnt;
struct node {
int ls, rs, v;
}A[maxn << 9];
void init() { cnt = 0; }
void change(int &nrt, int rt, int l, int r, int x) {
A[nrt = ++cnt] = A[rt], ++A[nrt].v;
if (l == r) return;
int mid = (l + r) >> 1;
if (x <= mid) change(A[nrt].ls, A[rt].ls, l, mid, x);
else change(A[nrt].rs, A[rt].rs, mid + 1, r, x);
}
int query(int a, int b, int c, int d, int l, int r, int k) {
if (l == r) return l;
int mid = (l + r) >> 1;
int tot = A[A[a].ls].v + A[A[b].ls].v - A[A[c].ls].v - A[A[d].ls].v;
if (k <= tot) return query(A[a].ls, A[b].ls, A[c].ls, A[d].ls, l, mid, k);
return query(A[a].rs, A[b].rs, A[c].rs, A[d].rs, mid + 1, r, k - tot);
}
}
int d[maxn], fa[maxn][17];
inline int lca(int x, int y) {
if (d[x] < d[y]) swap(x, y);
for (int i = 16; ~i; i--)
if (d[fa[x][i]] >= d[y]) x = fa[x][i];
if (x == y) return x;
for (int i = 16; ~i; i--)
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
bool v[maxn];
inline void dfs(int now, int f) {
v[now] = 1, fa[now][0] = f, d[now] = d[f] + 1;
for (int i = 1; i <= 16; i++) fa[now][i] = fa[fa[now][i - 1]][i - 1];
ST::change(rt[now], rt[f], 1, len, w[now]);
for (int son : g[now]) {
if (son == f) continue;
dfs(son, now);
}
}
int main() {
#ifdef xunzhen
freopen("forest.in", "r", stdin);
freopen("forest.out", "w", stdout);
#endif
n = read();
n = read(), m = read(), q = read();
for (int i = 1; i <= n; i++) Fa[i] = i, sz[i] = 1;
for (int i = 1; i <= n; i++) t[i] = w[i] = read();
sort(t + 1, t + n + 1);
len = unique(t + 1, t + n + 1) - t - 1;
for (int i = 1; i <= n; i++) w[i] = lower_bound(t + 1, t + len + 1, w[i]) - t;
for (int i = 1; i <= m; i++) {
int x = read(), y = read();
g[x].push_back(y);
g[y].push_back(x);
merge(x, y);
}
for (int i = 1; i <= n; i++) if (!v[find(i)]) dfs(find(i), 0);
int lans = 0;
for (int i = 1; i <= q; i++) {
static char op[10];
scanf("%s", op);
if (op[0] == ‘Q‘) {
int x = read() ^ lans, y = read() ^ lans, k = read() ^ lans, f = lca(x, y);
printf("%d
", lans = t[ST::query(rt[x], rt[y], rt[f], rt[fa[f][0]], 1, len, k)]);
} else {
int x = read() ^ lans, y = read() ^ lans;
if (sz[x] > sz[y]) swap(x, y);
g[x].push_back(y), g[y].push_back(x);
merge(x, y), dfs(x, y);
}
}
return 0;
}
以上是关于Luogu3302 [SDOI2013]森林的主要内容,如果未能解决你的问题,请参考以下文章