[Sdoi2013] Forest chair tree + heuristic merge

Description
has a forest with N nodes, and each node has a non-negative integer as a weight. Initially, there are M edges in the forest.
Perform T operations. There are two types of operations:
Q xyk Query all the weights on the path from point x to point y, what is the kth smallest weight. This operation ensures that point x and point y are connected, and there are at least k points on the path between these two nodes.
L xy connects an edge between point x and point y. It is guaranteed that after this is done, it is still a forest.
In order to reflect the online linearity of the program, we encrypt the input data. Let lastans be the result of the last output of the program, and lastans is 0 initially.
For an input operation Q xyk, its real operation is Q x^lastans y^lastans k^lastans.
For an input operation L xy, its real operation is L x^lastans y^lastans.


Sample Input
1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3
Q 3 5 1
Q 10 0 0
L 5 4
L 3 2
L 0 7
Q 9 2 5
Q 6 1 6


Sample Output
2
2
1
4
2


This question is heuristically merged, and the actual measurement does not heuristically merge T to death. . .
Since you are zeroing one set at a time, choose the smaller and go to the larger set.
Regarding the proof of the time complexity, you consider gradually adding up from the bottom layer, so each layer will only be combined n times, and then if you heuristically combine, you can ensure the balance of the tree, there are log(n) layers, so the time The complexity is roughly O(n log n^2)


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
const int maxn = 210000;

struct edge {
    int x, y, next;
} e[4 * maxn]; int len, last[maxn];
struct trnode {
    int lc, rc, c;
} t[60 * maxn]; int cnt, rt[maxn];
int n, fa[maxn][20], dep[maxn];
int a[maxn], b[maxn], tot[maxn], f[maxn];
char ss[11];

void ins(int x, int y) {
    e[++len].x = x; e[len].y = y;
    e[len].next = last[x]; last[x] = len;
}

int findfa(int x) {
    if(f[x] != x) f[x] = findfa(f[x]);
    return f[x];
}

int erfen(int x) {
    int l = 1, r = n, ans = 0;
    while(l <= r) {
        int mid = (l + r) / 2;
        if(b[mid] <= x) l = mid + 1, ans = mid;
        else r = mid - 1;
    }
    return ans;
}

void Link(int &u, int l, int r, int p) {
    if(!u) u = ++cnt;
    t[u].c++;
    if(l == r) return ;
    int mid = (l + r) / 2;
    if(p <= mid) Link(t[u].lc, l, mid, p);
    else Link(t[u].rc, mid + 1, r, p);
}

void Merge(int &u1, int u2) {
    if(!u1 || !u2) {u1 = u1 + u2; return ;}
    t[u1].c += t[u2].c;
    Merge(t[u1].lc, t[u2].lc);
    Merge(t[u1].rc, t[u2].rc);
}

void del(int u) {
    if(!u) return ;
    t[u].c = 0;
    del(t[u].lc); del(t[u].rc);
    t[u].lc = t[u].rc = 0;
}

void dfs(int x) {
    Link(rt[x], 1, n, a[x]); Merge(rt[x], rt[fa[x][0]]);
    for(int i = 1; i <= 18; i++) fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for(int k = last[x]; k; k = e[k].next) {
        int y = e[k].y;
        if(y != fa[x][0]) {
            fa[y][0] = x;
            dep[y] = dep[x] + 1;
            dfs(y);
        }
    }
}

void rebuild(int x) {
    del(rt[x]); Link(rt[x], 1, n, a[x]); Merge(rt[x], rt[fa[x][0]]);
    for(int i = 1; i <= 18; i++) fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for(int k = last[x]; k; k = e[k].next) {
        int y = e[k].y;
        if(y != fa[x][0]) {
            fa[y][0] = x;
            dep[y] = dep[x] + 1;
            rebuild(y);
        }
    }
}

int LCA(int x, int y) {
    if(dep[x] < dep[y]) swap(x, y);
    for(int i = 18; i >= 0; i--)
        if(dep[x] - dep[y] >= (1 << i))
            x = fa[x][i];
    if(x == y) return x;
    for(int i = 18; i >= 0; i--)
        if(fa[x][i] != fa[y][i])
            x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}

int query(int u1, int u2, int u3, int u4, int l, int r, int k) {
    if(l == r) return b[l];
    int mid = (l + r) / 2;
    int c = t[t[u1].lc].c + t[t[u2].lc].c - t[t[u3].lc].c - t[t[u4].lc].c;
    if(k <= c) return query(t[u1].lc, t[u2].lc, t[u3].lc, t[u4].lc, l, mid, k);
    else return query(t[u1].rc, t[u2].rc, t[u3].rc, t[u4].rc, mid + 1, r, k - c);
}

int main() {
    int tt = read(); n = read();
    int m = read(), t = read();
    for(int i = 1; i <= n; ++i) a[i] = read(), b[i] = a[i];
    sort(b + 1, b + n + 1);
    for(int i = 1; i <= n; ++i) a[i] = erfen(a[i]);
    for(int i = 1; i <= n; ++i) f[i] = i, tot[i] = 1;
    for(int i = 1; i <= m; ++i) {
        int x = read(), y = read();
        ins(x, y); ins(y, x);
        int fx = findfa(x), fy = findfa(y);
        if(fx != fy) {
            f[fx] = fy;
            tot[fy] += tot[fx];
        }
    }
    for(int i = 1; i <= n; ++i) {
        if(!dep[i]) dfs(i);
    }
    int lastans = 0;
    for(int i = 1; i <= t; ++i) {
        scanf("%s", ss + 1);
        if(ss[1] == 'Q') {
            int x = read(), y = read(), k = read();
            x ^= lastans, y ^= lastans, k ^= lastans;
            int lca = LCA(x, y);
            lastans = query(rt[x], rt[y], rt[lca], rt[fa[lca][0]], 1, n, k);
            printf("%d\n", lastans);
        }
        else {
            int x = read(), y = read();
            x ^= lastans; y ^= lastans;
            int fx = findfa(x), fy = findfa(y);
            if(tot[fx] > tot[fy]) swap(fx, fy), swap(x, y);
            tot[fy] += tot[fx]; f[fx] = fy;
            fa[x][0] = y; dep[x] = dep[y] + 1;
            rebuild(x);
            ins(x, y); ins(y, x);
        }
    }
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324581527&siteId=291194637