Count on a tree SPOJ - COT

原题链接

  • 题意:一棵树,每个点上有点权,然后求简单路径上第 \(k\) 小。
  • 题解:用的朴素做法,看到静态第 \(k\) 小,就用了主席树,然后在图上操作,要感性理解一下,用 \(lca\),即用 \(u,v\) 的版本然后剪掉双倍 \(lca\) 注意因为 \(lca\) 本身是包括的所以不要剪两倍的 \(lca\) 所以就是,每次剪掉 \(fa[lca][0]\)\(lca\) 这两棵树的就可以了。
  • 代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>


using namespace std;
const int N = 2e5 * 20;
int a[N], b[N], root[N], nn, dep[N];
struct President_Tree {
    int idx;
    struct node {
        int l, r, data;
    }tr[N];
    inline void create(int &p, int q, int l, int r, int num){
        p = ++idx;tr[p] = tr[q];tr[p].data++;
        if (l == r)return;
        int mid = l + r >> 1;
        if (num <= mid)create(tr[p].l, tr[q].l, l, mid, num);
        else create(tr[p].r, tr[q].r, mid+1, r, num);
    }
    inline int ask(int u, int v, int fa, int faa, int l, int r, int num) {
        int cnt = tr[tr[u].l].data + tr[tr[v].l].data - tr[tr[fa].l].data - tr[tr[faa].l].data;
        int mid = l + r >> 1;
        if (l == r)return r;
        if (num <= cnt)return ask(tr[u].l, tr[v].l, tr[fa].l, tr[faa].l, l, mid, num);
        else return ask(tr[u].r, tr[v].r, tr[fa].r, tr[faa].r, mid + 1, r, num-cnt);
    } 
}T;
vector<int>G[N];
int f[N][20];

void dfs(int u, int fa) {
    T.create(root[u], root[fa], 1, nn, a[u]);
    dep[u] = dep[fa] + 1;
    f[u][0] = fa;
    for (int i = 1; i <= 18; i++) {
        f[u][i] = f[f[u][i - 1]][i - 1];
    }
    for (int i = 0; i < G[u].size(); i ++ ) {
        int v = G[u][i];
        if (v == fa)continue;
        dfs(v, u);
    }

    return;
}
int Lca(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    for (int i = 18; i >= 0; i--) {
        if (dep[f[u][i]]>= dep[v])u = f[u][i];
    }
    if (u ==v)return v;
    for (int i = 18; i >=0; i--) {
        if (f[u][i]  != f[v][i]){
            u = f[u][i];v = f[v][i];
        }
    }
    return f[u][0];
}
signed main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++)scanf("%d", &a[i]),b[i] = a[i];
    sort(b + 1, b + 1 + n);
    nn = unique(b + 1, b + 1 + n) - b - 1;
    for (int i = 1; i <= n; i ++)a[i] = lower_bound(b + 1, b + 1 + nn, a[i]) - b;
    for (int i = 1; i < n; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, 0);
    for (int i = 1; i <= m; i ++) {
        int u, v, k;
        scanf("%d%d%d", &u, &v, &k);
        int lca = Lca(u, v);
        printf("%d\n", b[T.ask(root[u],root[v], root[lca], root[f[lca][0]], 1,nn, k)]);
    }
}
posted @ 2021-04-27 09:10  u_yan  阅读(28)  评论(0编辑  收藏  举报