https://vjudge.net/problem/SPOJ-COT
思路:以1为根,类似原来板子的按照线性序列去开新的主席树,这里按照图的先序遍历开新的主席树。一棵树表示该点到根节点的前缀关系。
那么寻找路径上的第k点,利用和LCA的前缀关系。
不过这里和之前https://blog.csdn.net/zstuyyyyccccbbbb/article/details/109882553这题有个共同的关于LCA点权的重复部分。
在这里通过LL sum=tree[tree[pre].l].sum+tree[tree[suf].l].sum-tree[tree[LCA].l].sum-tree[tree[LCAfather].l].sum;来达到维护到lca点权的目的。
代码上注意:query(root[u],root[v],root[LCA],root[FALCA],1,cnt,k);最开始扔进去的是root[],即该点对应的主席树根节点。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+1000;
typedef long long LL;
typedef pair<LL,LL>P;
///主席树部分
LL nodeid=0;
struct Tree{
LL l,r,sum;
}tree[maxn*20];
LL a[maxn],b[maxn],cnt=0;
LL root[maxn];
LL update(LL pre,LL l,LL r,LL x){
LL rt=++nodeid;
tree[rt].l=tree[pre].l;
tree[rt].r=tree[pre].r;
tree[rt].sum=tree[pre].sum+1;
LL mid=(l+r)>>1;
if(l<r){
if(x<=mid){
tree[rt].l=update(tree[pre].l,l,mid,x);
}
else tree[rt].r=update(tree[pre].r,mid+1,r,x);
}
return rt;
}
LL query(LL pre,LL suf,LL LCA,LL LCAfather,LL l,LL r,LL k){
if(l==r) return l;
LL sum=tree[tree[pre].l].sum+tree[tree[suf].l].sum-tree[tree[LCA].l].sum-tree[tree[LCAfather].l].sum;
/// debug(l);debug(r);
LL mid=(l+r)>>1;
if(sum>=k){///查第k小
return query(tree[pre].l,tree[suf].l,tree[LCA].l,tree[LCAfather].l,l,mid,k);
}
else return query(tree[pre].r,tree[suf].r,tree[LCA].r,tree[LCAfather].r,mid+1,r,k-sum);
}
///树剖部分求LCA
LL siz[maxn],son[maxn],top[maxn],fa[maxn],dep[maxn];
vector<LL>g[maxn];
void predfs(LL u,LL father){
siz[u]=1;dep[u]=dep[father]+1;
fa[u]=father;
for(LL i=0;i<g[u].size();i++){
LL v=g[u][i];
if(v==father) continue;
LL x=lower_bound(b+1,b+cnt+1,a[v])-b;
root[v]=update(root[u],1,cnt,x);
predfs(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]){
son[u]=v;
}
}
}
void dfs(LL u,LL topx){
top[u]=topx;
if(!son[u]) return;
dfs(son[u],topx);
for(LL i=0;i<g[u].size();i++){
LL v=g[u][i];
if(v==fa[u]||v==son[u]) continue;
dfs(v,v);
}
}
LL getLCA(LL u,LL v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
return u;
}
LL path_query(LL u,LL v,LL k){
///if(dep[u]>dep[v]) swap(u,v);
LL LCA=getLCA(u,v);
/// debug(LCA);
LL FALCA=fa[LCA];
debug(FALCA);
/// cout<<"fuck"<<endl;
debug(cnt);
return query(root[u],root[v],root[LCA],root[FALCA],1,cnt,k);
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL n,m;cin>>n>>m;
for(LL i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
cnt=unique(b+1,b+1+n)-b-1;
for(LL i=1;i<n;i++){
LL u,v;cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
LL x=lower_bound(b+1,b+1+cnt,a[1])-b;
root[1]=update(root[0],1,cnt,x);
predfs(1,0);
dfs(1,1);
/// cout<<"fuck"<<endl;
/// shuchu(1,1,cnt);
while(m--){
LL u,v,k;cin>>u>>v>>k;
///cout<<path_query(u,v,k)<<endl;
cout<<b[path_query(u,v,k)]<<endl;
}
return 0;
}