10628. Count on a treeProblem code: COT |
You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.
We will ask you to perform the following operation:
- u v k : ask for the kth minimum weight on the path from node u to node v
Input
In the first line there are two integers N and M.(N,M<=100000)
In the second line there are N integers.The ith integer denotes the weight of the ith node.
In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).
In the next M lines,each line contains three integers u v k,which means an operation asking for the kth minimum weight on the path from node u to node v.
Output
For each operation,print its result.
Example
Input:8 58 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 2 5 2 2 5 3 2 5 4 7 8 2
Output: 2 8 9 1057
求x到y路径上第k小的数,无修改。利用函数式线段树,可以把x到y的路径表示出来,也就是root[x]-root[fa[lca][0]]+root[y]-root[lca],lca是x,y的最近公共祖先,fa[lca][0]是lca的父亲。
#include <stdio.h> #include <string.h> #include <iostream> #include <string> #include <queue> #include <stack> #include <map> #include <vector> #include <stdlib.h> #include <algorithm> using namespace std; typedef long long ll; #define rep(i,s,t) for(int i=s;i<t;i++) #define red(i,s,t) for(int i=s-1;i>=t;i--) #define ree(i,now) for(int i=head[now];i!=-1;i=edge[i].next) #define clr(a,v) memset(a,v,sizeof a) #define MID(x,y) int mid=(x+y)>>1 inline int input(){ int ret=0;bool isN=0;char c=getchar(); while(c<'0' || c>'9'){ if(c=='-') isN=1; c=getchar(); } while(c>='0' && c<='9'){ ret=ret*10+c-'0'; c=getchar(); } return isN?-ret:ret; } inline void output(int x){ if(x<0){ putchar('-');x=-x; } int len=0,data[11]; while(x){ data[len++]=x%10;x/=10; } if(!len) data[len++]=0; while(len--) putchar(data[len]+48); putchar('\n'); } const int N=100005; const int M=5000005; int n,m,u,v,k,w[N]; int e,head[N]; int fa[N][20],dep[N]; struct EDGE{ int v,next; }edge[N<<1]; inline void addEdge(int u,int v){ edge[e].v=v; edge[e].next=head[u]; head[u]=e++; } int root[N]; int tot,s[M],ls[M],rs[M]; int y[N],cnt; inline void copy(int k,int p){ s[k]=s[p];ls[k]=ls[p];rs[k]=rs[p]; } inline int build(int x,int y){ int k=(++tot); s[k]=0; if(x!=y){ MID(x,y); ls[k]=build(x,mid); rs[k]=build(mid+1,y); } return k; } inline int add(int p,int l,int r,int x){ int k=(++tot);copy(k,p); s[k]++; if(l==r) return k; MID(l,r); if(x<=mid) ls[k]=add(ls[p],l,mid,x); else rs[k]=add(rs[p],mid+1,r,x); return k; } inline int query(int a,int b,int lca,int f,int l,int r,int k){ if(l==r) return l; int t=s[ls[a]]-s[ls[f]]+s[ls[b]]-s[ls[lca]]; MID(l,r); if(t>=k) return query(ls[a],ls[b],ls[lca],ls[f],l,mid,k); else return query(rs[a],rs[b],rs[lca],rs[f],mid+1,r,k-t); } inline void dfs(int now,int pre){ dep[now]=dep[pre]+1; fa[now][0]=pre; rep(i,1,20) fa[now][i]=fa[fa[now][i-1]][i-1]; root[now]=add(root[pre],1,cnt,w[now]); ree(i,now){ if(edge[i].v!=pre) dfs(edge[i].v,now); } } inline int LCA(int x,int y){ if(dep[x]>dep[y]) swap(x,y); int delta=dep[y]-dep[x]; rep(i,0,20){ if(delta & (1<<i)) y=fa[y][i]; } if(x==y) return x; red(i,20,0){ if(fa[x][i]==fa[y][i]) continue; x=fa[x][i]; y=fa[y][i]; } return fa[x][0]; } int main(){ while(~scanf("%d%d",&n,&m)){ clr(head,-1),e=cnt=0; rep(i,1,n+1){ w[i]=input(); y[++cnt]=w[i]; } sort(y+1,y+1+cnt); cnt=unique(y+1,y+1+cnt)-(y+1); rep(i,1,n+1) w[i]=lower_bound(y+1,y+cnt+1,w[i])-(y+1)+1; rep(i,1,n){ u=input(),v=input(); addEdge(u,v);addEdge(v,u); } fa[0][0]=dep[0]=0;tot=0; root[0]=build(1,cnt); dfs(1,0); rep(i,0,m){ u=input(),v=input(),k=input(); int lca=LCA(u,v); int f=fa[lca][0]; //cout<<u << " "<< v<< " "<< lca<< " "<<f<<endl; output(y[query(root[u],root[v],root[lca],root[f],1,cnt,k)]); } } return 0; }