给出一棵树,树上每个节点都有权值,有m个询问,求u到v的路径上第k大的数。
树上的第k大值,跟区间第k大有些不同,区间第k大每个值在前一个值的基础上新建一棵树,而树上第k大则是在父亲节点的基础上新建一棵树,子节点的主席树都是从底下根节点累加出来的
查询的时候,答案就是root[v] + root[u] - root[lca(v, u)] - root[fa[lca(v,u)]]上的第k大
为什么是这个结果,看这张图就明白了
红色圈出的分支就对应root[v] - root[fa[lca(u,v)]]
绿色圈出的分支对应root[u] - root[lca]
加在一起就是u - > v的主席树
// 树上的主席树
#include
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 1e5+5;
int A[maxn], B[maxn];
int tot;
// 树
int head[maxn], cnt1;
struct Edge{
int v, next;
}edges[maxn<<1];
void addEdge(int u, int v){
edges[cnt1].v = v;
edges[cnt1].next = head[u]; head[u] = cnt1++;
}
// 主席树
int lson[maxn<<5], rson[maxn<<5], Tree[maxn<<5], root[maxn];
int cnt;
void Build(int& rt, int l, int r){
rt = ++cnt; Tree[rt] = 0;
if(l == r) return;
int mid = (l+r) >> 1;
Build(lson[rt], l, mid);
Build(rson[rt], mid+1, r);
}
void update(int& new_rt, int old_rt, int l, int r, int pos){
new_rt = ++cnt;
lson[new_rt] = lson[old_rt]; rson[new_rt] = rson[old_rt];
Tree[new_rt] = Tree[old_rt] + 1;
if(l == r) return;
int mid = (l+r) >> 1;
if(pos <= mid) update(lson[new_rt], lson[old_rt], l, mid, pos);
else update(rson[new_rt], rson[old_rt], mid+1, r, pos);
}
int Query(int u, int v, int lca, int fa_lca, int l, int r, int k){
if(l == r) return l;
int mid = (l+r) >> 1;
int leftot = Tree[lson[u]] + Tree[lson[v]] - Tree[lson[lca]] - Tree[lson[fa_lca]];
if(k <= leftot) return Query(lson[u], lson[v], lson[lca], lson[fa_lca], l, mid, k);
return Query(rson[u], rson[v], rson[lca], rson[fa_lca], mid+1, r, k-leftot);
}
bool vis[maxn];
int num; // 计数访问次序
int vis_order[maxn]; // vis_order[x]: x节点的访问次序
int ver[maxn<<1]; // ver[x]: 第x个访问的是哪个节点
int depth[maxn<<1]; // depth[x]: 第x个访问的节点的深度
int fa[maxn]; // fa[x]:x的父节点
void dfs(int u, int dad, int level){
vis[u] = 1; vis_order[u] = ++num; ver[num] = u; depth[num] = level; fa[u] = dad;
update(root[u], root[dad], 1, tot, A[u]); //在父节点的基础上建树
for(int i = head[u]; i != -1; i = edges[i].next){
int v = edges[i].v;
if(!vis[v]){
dfs(v, u, level+1);
ver[++num] = u; depth[num] = level; // 回溯上来又经过u
}
}
}
int dp[20][maxn<<1];
void ST(int n){
for(int i = 1; i <= n; ++i) dp[0][i] = i;
for(int i = 1; (1< v) swap(u, v);
int t = RMQ(u, v);
return ver[t];
}
int main()
{
int n, m;
int u,v,k;
while(scanf("%d%d",&n,&m) == 2&&n){
for(int i = 1; i <= n; ++i) scanf("%d", &A[i]), B[i] = A[i];
// 离散化
sort(B+1, B+n+1);
tot = unique(B+1, B+n+1) - (B+1);
for(int i = 1; i <= n; ++i) A[i] = lower_bound(B+1, B+tot+1, A[i]) - B;
// 读入边
cnt1 = 0;
memset(head, -1, sizeof(head));
for(int i = 1; i < n; ++i){
scanf("%d%d",&u,&v);
addEdge(u, v); addEdge(v, u);
}
// 建主席树
cnt = 0;
Build(root[0], 1, tot); // 初始化
num = 0;
memset(vis, 0, sizeof(vis));
dfs(1, 0, 1); // 子树在父节点的基础上建立
//for(int i = 1; i <= 2*n-1; ++i) printf("%d ", depth[i]) ;puts("");
// LCA初始化
ST(2*n-1);
//for(int i = 1; i <= 2*n-1; ++i) printf("%d ", dp[1][i]) ;
// 查询
for(int i = 1; i <= m; ++i){
scanf("%d%d%d", &u,&v,&k);
int lca = LCA(u, v);
int t = Query(root[u], root[v], root[lca], root[fa[lca]], 1, tot, k);
printf("%d\n", B[t]);
}
}
fclose(stdin);
return 0;
}