树上第k大/小(主席树)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
int T[maxn],L[maxn*44],R[maxn*44],sum[maxn*44];
int a[maxn],b[maxn],f[maxn][22],dep[maxn],e,len,tot;
int to[maxn*2],head[maxn],nxt[maxn*2];
void add(int u,int v)
{
    e++;
    to[e]=v;
    nxt[e]=head[u];
    head[u]=e;
}
void update(int &rt,int pre,int l,int r,int x)
{
    rt=++tot;
    L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+1;
    if(l==r) return ;
    int mid=(l+r)/2;
    if(x<=mid) update(L[rt],L[pre],l,mid,x);
    else update(R[rt],R[pre],mid+1,r,x);
}
 
int query(int gen_fa,int gen,int ql,int qr,int l,int r,int k)
{
    if(l==r) return l;
    int res=sum[L[ql]]+sum[L[qr]]-sum[L[gen_fa]]-sum[L[gen]];
    int mid=(l+r)/2;
    if(res>=k) return query(L[gen_fa],L[gen],L[ql],L[qr],l,mid,k);
    else return query(R[gen_fa],R[gen],R[ql],R[qr],mid+1,r,k-res);
}
 
void dfs(int v,int fa)
{
 
    f[v][0]=fa;
    dep[v]=dep[fa]+1;
    update(T[v],T[fa],1,len,lower_bound(b+1,b+len+1,a[v])-b);
 
    for(int i=1;(1<<i)<=dep[v];i++)
    {
        f[v][i]=f[f[v][i-1]][i-1];
    }
 
    for(int i=head[v];i!=-1;i=nxt[i])
    {
        if(to[i]==fa) continue;
        dfs(to[i],v);
    }
}
 
int lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    int d=dep[u]-dep[v];
    for(int i=0;(1<<i)<=d;i++)
    {
        if((1<<i)&d) u=f[u][i];
    }
    if(u==v) return u;
    for(int i=20;i>=0;i--)
    {
        if(f[u][i]!=f[v][i])
        {
            u=f[u][i];
            v=f[v][i];
        }
    }
    return f[u][0];
} 
int main()
{
	int TT;
	scanf("%d",&TT);
	while(TT--){
		memset(head,-1,sizeof head);
//		memset(T,0,sizeof(T));
		memset(L,0,sizeof(L));
		memset(R,0,sizeof(R));
		memset(sum,0,sizeof(sum));
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(f,0,sizeof(f));
		memset(dep,0,sizeof(dep));
		memset(to,0,sizeof(to));
		memset(nxt,0,sizeof(nxt));
    	e=tot=0;
    	int n,m;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
        	scanf("%d",&a[i]);
        	b[i]=a[i];
    	}
    	sort(b+1,b+n+1);
    	len=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n-1;i++){
        	int u,v;
        	scanf("%d%d",&u,&v);
        	add(u,v);
        	add(v,u);
    	}
    	dfs(1,0);
    	int ans=0;
   		while(m--)
    	{
        	int ql,qr,k;
        	scanf("%d%d%d",&ql,&qr,&k);
        	int gen=lca(ql,qr);
        	int tt=dep[ql]+dep[qr]-2*dep[gen];//ql到qr有多少个节点数  
        	tt++;//因为tt会少一个节点点数 
        	if(k>tt) printf("-1\n");
        	else{
        		//从大到小第k大 
        		ans=b[query(T[f[gen][0]],T[gen],T[ql],T[qr],1,len,tt-k+1)];
        		printf("%d\n",ans);
			}
    	}
	} 
    return 0;
}
/*
10
8 1000
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
有T组操作  所以尽量有用数组表示不用结构体 这样好复制
n个结点 m个询问
n-1个 u v相连的点
m个询问 u v k(u到v第k是多少) 
*/ 

猜你喜欢

转载自blog.csdn.net/CC_1012/article/details/89258370
今日推荐