洛谷 P2633 Count on a tree
思路
看到路径上\(k\)小值,首先想到主席树
不会主席树的建议来这里看一下【AgOHの数据结构】主席树(友情提示:此链接为B站视频
但是这是棵树,并不是序列,我们应该怎么办呢?
显然,我们可以像序列前缀和一样,建立树上前缀和:以点的\(dfs\)序为下标,以点权为区间建立主席树。
那么查询时\((x,y)\)这条链间的点数就是
\[sum[x]+sum[y]-sum[lca]-sum[fa[lca]]
\]
这里用到了一点点树上差分的思想,自己思考一下
至于\(LCA\),用树剖或者倍增求一下就好了
然后查询的时候就可以像序列上一样了
代码
/*
Author:Loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
struct node { int to, nxt; } e[A];
int n, m, head[A], cnt/*边数*/, tcnt/*主席树数*/, tot/*离散化之后*/;
int a[A], b[A], lastans;
inline void add(int from, int to) {
e[++cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
/*主席树*/
int root[A];
struct tree { int l, r, sum; } t[A * 10];
inline int getid(int x) {
return lower_bound(b + 1, b + 1 + tot, x) - b;
}
void insert(int &now, int pre, int l, int r, int pos) {
t[++tcnt] = t[pre], t[now = tcnt].sum++;
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) insert(t[now].l, t[pre].l, l, mid, pos);
else insert(t[now].r, t[pre].r, mid + 1, r, pos);
}
int query(int x, int y, int lca, int fa_lca, int l, int r, int k) {
if (l == r) return l;
int mid = (l + r) >> 1;
int tmp = t[t[x].l].sum + t[t[y].l].sum - t[t[lca].l].sum - t[t[fa_lca].l].sum;
if (k <= tmp) query(t[x].l, t[y].l, t[lca].l, t[fa_lca].l, l, mid, k);
//debug:k<=tmp写成k>=tmp
else query(t[x].r, t[y].r, t[lca].r, t[fa_lca].r, mid + 1, r, k - tmp);
}
/*树剖*/
int dep[A], fa[A], top[A], siz[A], son[A];
void prepare(int x, int f) {
dep[x] = dep[f] + 1, fa[x] = f, siz[x] = 1;
insert(root[x], root[fa[x]], 1, n, getid(a[x]));
for (int i = head[x]; i; i = e[i].nxt) {
int to = e[i].to;
if (to == f) continue;
prepare(to, x), siz[x] += siz[to];
//debug:prepare写成dfs
if (siz[to] > siz[son[x]]) son[x] = to;
}
}
void dfs(int x, int tp) {
top[x] = tp;
if (son[x]) dfs(son[x], tp);
for (int i = head[x]; i; i = e[i].nxt) {
int to = e[i].to;
if (to == fa[x] || to == son[x]) continue;
dfs(to, to);
}
}
int LCA(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
return x;
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++) b[i] = a[i] = read();
for (int i = 1; i < n; i++) {
int x = read(), y = read();
add(x, y), add(y, x);
}
sort(b + 1, b + 1 + n);
tot = unique(b + 1, b + 1 + n) - b - 1;
prepare(1, 0), dfs(1, 1);
while (m--) {
int x = read(), y = read(), k = read();
x ^= lastans;
int lca = LCA(x, y);
lastans = b[query(root[x], root[y], root[lca], root[fa[lca]], 1, n, k)];
cout << lastans << '\n';
}
return 0;
}
转载不必联系作者,但请声明出处