Count On A Tree 1
题意
给定一颗带点权有根树,每次查询两点之间路径上点权的第\(k\)大值
解法
求第\(k\)大?我们立刻想到主席树
但是这是树上的问题,我们怎么进行操作呢?
我们令每一颗主席树维护当前节点到根节点路径上的点权,那么每个点的主席树都由其父亲转移过来
那么怎么查询\(x,y\)两个结点路径上的第\(k\)大点权呢?
我们发现,想要获得\(x,y\)两个结点之间的路径对应的主席树,我们不能简单的提取\(x,y\)这两个点对应的主席树进行计算,因为我们会发现在之前的定义下,有一些多余的结点也算了进来:就是它们的\(lca\)到根节点路径上的点
那么我们在线段树上二分时现在需要传入三个点所对应的主席树\(x,y,LCA(x,y)\),每次减去\(LCA(x,y)\)上对应的结点
但是这样我们会发现\(LCA\)也是\(x,y\)路径上的结点,而它被多减了一次
所以我们还需要传入\(LCA\)的父亲参与线段树上二分
把整个过程可以理解为一个前缀和的操作(本身主席树就利用的是前缀和的思想)
最后成功的将\(x,y\)的路径提取出来
代码
#include <iostream>
#include <algorithm>
using namespace std;
void fast_IO();
const int N = 2e5 + 10;
int n, m, t, lstans;
int a[N], rt[N];
int w[N], dep[N], f[N][25];
int cap;
int head[N], to[N], nxt[N];
struct CTree {
int sz;
int ls[N * 20], rs[N * 20], val[N * 20];
void clear() { sz = 0; }
int newnode() {
++sz;
ls[sz] = rs[sz] = val[sz] = 0;
return sz;
}
void mkchain(int &x, int y, int l, int r, int k) {
x = newnode();
ls[x] = ls[y], rs[x] = rs[y], val[x] = val[y] + 1;
if (l == r) return;
int mid = l + r >> 1;
if (k <= mid)
mkchain(ls[x], ls[y], l, mid, k);
else
mkchain(rs[x], rs[y], mid + 1, r, k);
}
int query(int x, int y, int z, int fz, int l, int r, int k) {
if (l == r) return l;
int tot = val[ls[x]] - val[ls[z]] + val[ls[y]] - val[ls[fz]];
int mid = l + r >> 1;
if (k <= tot)
return query(ls[x], ls[y], ls[z], ls[fz], l, mid, k);
else
return query(rs[x], rs[y], rs[z], rs[fz], mid + 1, r, k - tot);
}
} tr;
inline void add(int x, int y) {
to[++cap] = y, nxt[cap] = head[x], head[x] = cap;
}
void discre() {
for (int i = 1; i <= n; ++i) a[i] = w[i];
sort(a + 1, a + n + 1);
t = unique(a + 1, a + n + 1) - a - 1;
for (int i = 1; i <= n; ++i)
w[i] = lower_bound(a + 1, a + t + 1, w[i]) - a;
}
void DFS(int x, int fa) {
tr.mkchain(rt[x], rt[fa], 1, t, w[x]);
dep[x] = dep[fa] + 1, f[x][0] = fa;
for (int i = 1; i <= 20; ++i) f[x][i] = f[f[x][i - 1]][i - 1];
for (int i = head[x]; i; i = nxt[i])
if (to[i] != fa) DFS(to[i], x);
}
int LCA(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 20; i >= 0; --i)
if (dep[f[x][i]] >= dep[y]) x = f[x][i];
if (x == y) return y;
for (int i = 20; i >= 0; --i)
if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int main() {
fast_IO();
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> w[i];
discre();
int x, y;
for (int i = 1; i < n; ++i) {
cin >> x >> y;
add(x, y), add(y, x);
}
tr.clear();
DFS(1, 0);
int k, lca, flca;
for (int i = 1; i <= m; ++i) {
cin >> x >> y >> k;
x ^= lstans;
lca = LCA(x, y), flca = f[lca][0];
cout << (lstans = a[tr.query(rt[x], rt[y], rt[lca], rt[flca], 1, t, k)]) << endl;
}
return 0;
}
void fast_IO() {
ios :: sync_with_stdio(false);
cin.tie(NULL), cout.tie(NULL);
}