题目 链接
题意:求树上的路径 u->v上第k小的节点
分析:普通的第K大,当前的这颗线段树是在前面一颗线段树的基础上建立的,而树上的第K大,当前的线段树可以在其父节点的线段树建立起来。所以我们查询u->v上的第k大就是rt[u]+rt[v]-rt[lca(u,v)]-rt[fa[lca(u,v)]]的第k大。
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=2e5+10;
int n,q;
int a[maxn],ha[maxn];
int sum[maxn*40],ls[maxn*40],rs[maxn*40],rt[maxn*40];
int tot;
int sz;
//主席树
void build (int &num,int l,int r){
num=++tot;
sum[num]=0;
if (r==l)return;
int mid=(l+r)/2;
build (ls[num],l,mid);
build (rs[num],mid+1,r);
}
void update(int &num,int l,int r,int last,int pos){
num=++tot;
ls[num]=ls[last];
rs[num]=rs[last];
sum[num]=sum[last]+1;
if (l==r)return ;
int mid=(l+r)/2;
if (pos<=mid)update(ls[num],l,mid,ls[last],pos);
else update(rs[num],mid+1,r,rs[last],pos);
}
int query(int u,int v,int lca,int lcafa,int l,int r,int k){
if (l==r)return l;
int mid=(l+r)/2;
int cnt=sum[ls[u]]+sum[ls[v]]-sum[ls[lca]]-sum[ls[lcafa]];
if (cnt>=k)return query(ls[u],ls[v],ls[lca],ls[lcafa],l,mid,k);
else return query(rs[u],rs[v],rs[lca],rs[lcafa],mid+1,r,k-cnt);
}
//LCA
int dis[maxn];//dis[i]表示节点i到树根的距离
int dp[maxn*2][20];
int first[maxn];//first[i]表示i这个节点第一次出现的标号
int dep[maxn*2];//深度
int point[maxn*2];//point[i]表示标号为i所对应的节点
int vis[maxn];//标记节点是否被访问过了
int cnt;//遍历是节点的数目
int fa[maxn];
vector<int>G[maxn];
void dfs(int u,int father,int idx){
vis[u]=true;
point[++cnt]=u;//point表示节点的标号
first[u]=cnt;//first表示u这个节点第一次出现的位置
dep[cnt]=idx;//深度
fa[u]=father;
update(rt[u],1,sz,rt[father],a[u]);
for (int i=0;iint v=G[u][i];
if (!vis[v]){
dfs(v,u,idx+1);
point[++cnt]=u;
dep[cnt]=idx;
}
}
}
void RMQ_init(int n){
for (int i=1;i<=n;i++)dp[i][0]=i;
for (int k=1;(1<for (int i=1;i+(1<1<=n;i++){
int a=dp[i][k-1];
int b=dp[i+(1<<(k-1))][k-1];
if (dep[a]>dep[b])dp[i][k]=b;
else dp[i][k]=a;
}
}
}
int RMQ(int l,int r){
int k=0;
while ((1<<(k+1))<=r-l+1)k++;
int a=dp[l][k];
int b=dp[r-(1<1][k];//保存的是编号
return dep[a]>dep[b]?b:a;
}
int LCA(int u,int v){//求LCA
int x=first[u],y=first[v];
if (x>y)swap(x,y);
int ans=RMQ(x,y);
return point[ans];
}
int main()
{
while (scanf ("%d%d",&n,&q)!=EOF){
for (int i=0;i<=n;i++)G[i].clear();
memset (vis,0,sizeof (vis));
for (int i=1;i<=n;i++){
scanf ("%d",&a[i]);
ha[i]=a[i];
}
int u,v,k;
for (int i=0;i1;i++){
scanf ("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
sort(ha+1,ha+1+n);
sz=unique(ha+1,ha+1+n)-(ha+1);
for (int i=1;i<=n;i++){
a[i]=lower_bound(ha+1,ha+1+sz,a[i])-ha;
}
tot=cnt=0;
build(rt[0],1,sz);
dfs(1,0,1);
RMQ_init(2*n-1);
while (q--){
scanf ("%d%d%d",&u,&v,&k);
int lca=LCA(u,v);
int ans=query(rt[u],rt[v],rt[lca],rt[fa[lca]],1,sz,k);
printf ("%d\n",ha[ans]);
}
}
return 0;
}
/*
8 6
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
2 5 2
2 5 3
2 5 4
7 8 2
5 7 1
*/