Spoj 10628. Count on a tree HYSBZ - 2588
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
Input
第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
Output
M行,表示每个询问的答案。最后一个询问不输出换行符
Sample Input
8 5
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
0 5 2
10 5 3
11 5 4
110 8 2
Sample Output
2
8
9
105
7
Hint
HINT:
N,M<=100000
暴力自重。。。
题意:求树上两节点间的第k大值
思路:因为没有修改,所以直接剖分,并建主席树,v,u之间新数的个数:sum[u] + sum[v] - sum[lca(u , v)] - sum[fa[lca(u , v)]],不多说,代码不长,直接上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100005;
struct Edge
{
int a,b,pre;
}edge[2*N];
struct Node
{
int l,r,sum;
}tree[30*N];
int dis[N],pre[N],fa[N],son[N],siz[N],top[N],wei[N],root[N],len[N],number[N],wei_num,edge_num,node_num,num;
void addedge(int a,int b)
{
edge[++edge_num]={a,b,pre[a]};
pre[a]=edge_num;
}
void addtree(int l,int r,int &node,int pre,int p)
{
node=++node_num;
tree[node]=tree[pre];
tree[node].sum+=1;
if(l==r)return;
int mid=(l+r)>>1;
if(p<=mid) addtree(l,mid,tree[node].l,tree[pre].l,p);
else addtree(mid+1,r,tree[node].r,tree[pre].r,p);
}
int query(int ll,int rr,int u,int v,int l,int f,int k)
{
if(ll==rr)return ll;
int nn=tree[tree[u].l].sum+tree[tree[v].l].sum-tree[tree[l].l].sum-tree[tree[f].l].sum;
int mid=(ll+rr)>>1;
if(k<=nn)return query(ll,mid,tree[u].l,tree[v].l,tree[l].l,tree[f].l,k);
else return query(mid+1,rr,tree[u].r,tree[v].r,tree[l].r,tree[f].r,k-nn);
}
void dfs1(int u,int f,int d)
{
dis[u]=d;
fa[u]=f;
son[u]=0;
siz[u]=1;
int p=lower_bound(number+1,number+1+num,len[u])-number;
addtree(1,num,root[u],root[f],p);
for(int i=pre[u];i;i=edge[i].pre){
int v=edge[i].b;
if(v==f)continue;
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
wei[u]=++wei_num;
if(son[u])dfs2(son[u],tp);
for(int i=pre[u];i;i=edge[i].pre){
int v=edge[i].b;
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
int yongth(int a,int b)
{
for(;top[a]!=top[b];dis[top[a]]>dis[top[b]]?(a=fa[top[a]]):(b=fa[top[b]]));
return dis[a]<dis[b]?a:b;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&len[i]);
number[i]=len[i];
}
int a,b;
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
sort(number+1,number+1+n);
num=unique(number+1,number+1+n)-number-1;
dfs1(1,0,1);
wei_num=0;
dfs2(1,1);
int last=0,u,v,k;
while(q--){
scanf("%d%d%d",&u,&v,&k);
u^=last;
int lca=yongth(u,v);
last=number[query(1,num,root[u],root[v],root[lca],root[fa[lca]],k)];
printf("%d",last);
if(q!=0)printf("\n");
}
return 0;
}