Luogu3302 [SDOI2013]森林

题目蓝链

Description

给你一个森林,你需要支持两个操作:

  1. 查询一条路径上第\(k\)小的权值是多少

  2. 连接两个点

强制在线

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\n", 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;
}

猜你喜欢

转载自www.cnblogs.com/xunzhen/p/10322505.html