「解题报告」[省选联考 2021 A/B 卷] 宝石

简单题。

考虑只往上跳怎么做。由于当收集了某个宝石之后,后面的路径就是固定的了,于是我们预处理出每个点的下一个能够收集宝石的地方在哪里,然后倍增即可。

现在有上有下,那么树剖一下,对每条链预处理出倍增数组,然后每次在一条链上倍增即可。

今天模拟赛的 T1 刚好和这题做法一模一样 我做题的时机挺神奇(

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int n, m, c, q;
int p[MAXN], np[MAXN];
int w[MAXN];
struct Graph {
    vector<int> e[MAXN];
    void add(int u, int v) {
        e[u].push_back(v);
    }
    int fa[MAXN], dep[MAXN], siz[MAXN], son[MAXN];
    int top[MAXN], dfn[MAXN], dcnt, idf[MAXN];
    int f[MAXN][22], g[MAXN][22];
    void dfs1(int u, int pre) {
        fa[u] = pre, dep[u] = dep[pre] + 1, siz[u] = 1;
        for (int v : e[u]) if (v != pre) {
            dfs1(v, u);
            siz[u] += siz[v];
            if (siz[v] > siz[son[u]]) son[u] = v;
        }
    }
    void dfs2(int u, int pre, int t) {
        top[u] = t, dfn[u] = ++dcnt, idf[dcnt] = u;
        if (son[u]) dfs2(son[u], u, t);
        for (int v : e[u]) if (v != pre && v != son[u]) {
            dfs2(v, u, v);
        }
    }
    vector<int> pos[MAXN];
    void decomposition() {
        dfs1(1, 0), dfs2(1, 0, 1);
        for (int i = 1; i <= n; i++) {
            pos[w[i]].push_back(dfn[i]);
        }
        for (int i = 1; i <= c; i++) {
            sort(pos[i].begin(), pos[i].end());
        }
        for (int i = 1; i <= n; i++) {
            int nc = p[np[w[i]] + 1];
            auto nxt = lower_bound(pos[nc].begin(), pos[nc].end(), dfn[i]);
            if (nxt != pos[nc].begin()) {
                f[i][0] = idf[*prev(nxt)];
            }
            nxt = upper_bound(pos[nc].begin(), pos[nc].end(), dfn[i]);
            if (nxt != pos[nc].end()) {
                g[i][0] = idf[*nxt];
            }
        }
        for (int j = 1; j <= 20; j++) {
            for (int i = 1; i <= n; i++) {
                f[i][j] = f[f[i][j - 1]][j - 1];
                g[i][j] = g[g[i][j - 1]][j - 1];
            }
        }
    }
    struct Seg {
        int l, r;
    };
    int query(int u, int v) {
        int x = u, y = v;
        vector<Seg> up, down;
        while (top[x] != top[y]) {
            if (dep[top[x]] > dep[top[y]]) {
                up.push_back({dfn[top[x]], dfn[x]});
                x = fa[top[x]];
            } else {
                down.push_back({dfn[top[y]], dfn[y]});
                y = fa[top[y]];
            }
        }
        if (dep[x] > dep[y]) up.push_back({dfn[y], dfn[x]});
        else down.push_back({dfn[x], dfn[y]});
        reverse(down.begin(), down.end());
        int c = 1;
        for (auto s : up) {
            auto nxt = upper_bound(pos[p[c]].begin(), pos[p[c]].end(), s.r);
            if (nxt != pos[p[c]].begin() && *prev(nxt) >= s.l) {
                int t = idf[*prev(nxt)];
                for (int i = 20; i >= 0; i--) if (f[t][i] && dfn[f[t][i]] >= s.l)
                    t = f[t][i];
                c = np[w[t]] + 1;
            }
        }
        for (auto s : down) {
            auto nxt = lower_bound(pos[p[c]].begin(), pos[p[c]].end(), s.l);
            if (nxt != pos[p[c]].end() && *nxt <= s.r) {
                int t = idf[*nxt];
                for (int i = 20; i >= 0; i--) if (g[t][i] && dfn[g[t][i]] <= s.r)
                    t = g[t][i];
                c = np[w[t]] + 1;
            }
        }
        return c - 1;
    }    
} g;

int main() {
    scanf("%d%d%d", &n, &m, &c);
    for (int i = 1; i <= c; i++) {
        scanf("%d", &p[i]);
        np[p[i]] = i;
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", &w[i]);
    }
    for (int i = 1; i < n; i++) {
        int u, v; scanf("%d%d", &u, &v);
        g.add(u, v);
        g.add(v, u);
    }
    g.decomposition();
    scanf("%d", &q);
    while (q--) {
        int u, v; scanf("%d%d", &u, &v);
        printf("%d\n", g.query(u, v));
    }
    return 0;
}
posted @ 2023-02-13 15:18  APJifengc  阅读(27)  评论(0编辑  收藏  举报