转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:给出一棵树,问两个节点之间路径经过的结点的权值的第k小的数。
为了做这题,先去学了一下DFS+RMQ的LCA求法。
这题和普通的第K大类似。
普通的第K大,是从后往前建立主席树,前一个在后一个的基础上修改。
而树上第K大,依旧是每个结点一棵主席树,是在父节点的基础上修改。
那么可以发现这棵主席树是包括所有祖先结点的(就是深度在当前结点之上的)
查询的时候,是两个结点的值的和,还要减掉lca以上的部分。同时要注意处理lca这个 结点的值。
主要不同便是建树是根据父结点,以前查询的时候注意两个主席树的公共部分。
至于我写的效率略低啊,不加输入外挂会TLE。。。
SPOJ的运行速度,勉强卡过
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<stack>
#include<string>
#include<ctime>
#include<queue>
#include<cassert>
#define inf 1000000005
#define M 10000005
#define N 110005
#define maxn 210005
#define eps 1e-8
#define zero(a) fabs(a)<eps
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
#define sqr(a) ((a)*(a))
#define Key_value ch[ch[root][1]][0]
#define test puts("OK");
#define pi acos(-1.0)
#define lowbit(x) ((-(x))&(x))
#define HASH1 1331
#define HASH2 10001
#define C 240
#define vi vector<int>
#define TIME 10
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
void scanf_(int &num){
char in;
while((in=getchar())>'9'||in<'0');
num=in-'0';
while(in=getchar(),in>='0'&&in<='9')
num*=10,num+=in-'0';
}
int n,q,a[N];
vi edge[N];
/* HASH部分 */
int t[N],m;
void Init_hash(){
for(int i=1;i<=n;i++)
t[i]=a[i];
sort(t+1,t+1+n);
m=unique(t+1,t+1+n)-t-1;
}
int hash(int x){
return lower_bound(t+1,t+1+m,x)-t;
}
/* HASH部分 */
/* 主席树部分 */
int T[M],lson[M],rson[M],c[M],tot=0;
int bulid(int l,int r){
int root=tot++;
c[root]=0;
if(l!=r){
int mid=(l+r)>>1;
lson[root]=bulid(l,mid);
rson[root]=bulid(mid+1,r);
}
return root;
}
int update(int root,int pos,int val){
int newroot=tot++,tmp=newroot;
c[newroot]=c[root]+val;
int l=1,r=m;
while(l<r){
int mid=(l+r)>>1;
if(pos<=mid){
lson[newroot]=tot++;rson[newroot]=rson[root];
newroot=lson[newroot];root=lson[root];
r=mid;
}
else{
rson[newroot]=tot++;lson[newroot]=lson[root];
newroot=rson[newroot];root=rson[root];
l=mid+1;
}
c[newroot]=c[root]+val;
}
return tmp;
}
int query(int left_root,int right_root,int LCA,int k){
int lca_root=T[LCA],pos=hash(a[LCA]);
int l=1,r=m;
while(l<r){
int mid=(l+r)>>1;
int t=c[lson[left_root]]+c[lson[right_root]]-2*c[lson[lca_root]]+(pos>=l&&pos<=mid);
if(t>=k){
left_root=lson[left_root];
right_root=lson[right_root];
lca_root=lson[lca_root];
r=mid;
}
else{
k-=t;
left_root=rson[left_root];
right_root=rson[right_root];
lca_root=rson[lca_root];
l=mid+1;
}
}
return l;
}
/* 主席树部分 */
/* LCA部分 */
int depth=0,b[N*2],cnt=0;
int p[N],f[N];
void dfs(int u,int pre){
int t=++depth;
b[++cnt]=t;
f[t]=u;
p[u]=cnt;
T[u]=update(T[pre],hash(a[u]),1);
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i];
if(v==pre) continue;
dfs(v,u);
b[++cnt]=t;
}
}
int dp[N*2][20];
void Init_rmq(int n){
for(int i=1;i<=n;i++)
dp[i][0]=b[i];
int m=floor(log(n*1.0)/log(2.0));
for(int j=1;j<=m;j++)
for(int i=1;i<=n-(1<<j)+1;i++)
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int rmq(int l,int r){
int k=floor(log((r-l+1)*1.0)/log(2.0));
return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int lca(int a,int b){
if(p[a]>p[b]) swap(a,b);
return f[rmq(p[a],p[b])];
}
/* LCA部分 */
int main(){
scanf_(n);scanf_(q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<n;i++){
int u,v;
scanf_(u);scanf_(v);
edge[u].pb(v);
edge[v].pb(u);
}
Init_hash();
T[0]=bulid(1,m);
dfs(1,0);
Init_rmq(cnt);
while(q--){
int u,v,k;
scanf_(u);scanf_(v);scanf_(k);
printf("%d\n",t[query(T[u],T[v],lca(u,v),k)]);
}
return 0;
}