Time Limit: 129MS | Memory Limit: 1572864KB | 64bit IO Format: %lld & %llu |
Description
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 5
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 2 5 2 2 5 3 2 5 4 7 8 2
Output: 2 8 9 105 7
题意:求树上的边[u,v]中点权第k大
使用的是主席树+LCA(RMQ.dfs),然后去专门看了下RMQ+dfs实现LCA
用一个数组记录深度,然后记录搜索的路径,如果要找[a,b]中的LCA,直接找[a,b]中的深度最小值即可
参考:算法之LCA与RMQ问题
/* 主席树-代码参考kuangbin大神 在本题中相当于按树的节点来构建线段树,每个节点基于它的父亲进行构建 然后节点a保存的便是根到a的情况,于是乎我们T[a]+T[b]-2*T[lca(a,b)]即可 而且对lca节点进行一个判断。 hhh-2016-02-18 21:11:14 */ #include <functional> #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <cmath> using namespace std; const int maxn = 200010; int n,m; int a[maxn],t[maxn]; int T[maxn*40],val[maxn*40],lson[maxn*40],rson[maxn*40]; int Tot; void ini_hash() //排序去重 { for(int i =1; i <= n; i++) t[i] = a[i]; sort(t+1,t+n+1); m = unique(t+1,t+n+1)-t-1; } int Hash(int x) //获得x在排序去重后的位置 { return lower_bound(t+1,t+m+1,x) - t; } int build(int l,int r) { int root = Tot++; val[root] = 0; if(l != r) { int mid = (l+r)>>1; lson[root] = build(l,mid); rson[root] = build(mid+1,r); } return root; } //如果那里发生改变则兴建一个节点而非像平常修改那个节点的值 int update(int root,int pos,int va) { int newroot = Tot++; int tmp = newroot; val[newroot] = val[root] + va; 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 { lson[newroot] = lson[root]; rson[newroot] = Tot++; newroot = rson[newroot]; root = rson[root]; l = mid+1; } val[newroot] = val[root] + va; } return tmp; } int query(int lt,int rt,int lca,int k) { int lca_rt = T[lca]; int pos = Hash(a[lca]); int l = 1, r = m; while(l < r) { int mid = (l+r)>>1; int tmp = val[lson[lt]]+val[lson[rt]]-2*val[lson[lca_rt]]+(pos>=l&&pos<=mid); if(tmp >= k) { lt = lson[lt]; rt = lson[rt]; lca_rt = lson[lca_rt]; r = mid; } else { k -= tmp; l = mid+1; lt = rson[lt]; rt = rson[rt]; lca_rt = rson[lca_rt]; } } return l; } int rmq[maxn*2]; //表示深度 struct ST { int mm[maxn*2]; int dp[maxn*2][20]; void ini(int n) { mm[0] = -1; for(int i = 1; i <= n; i++) { mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1]; dp[i][0] = i; } for(int j = 1; j <= mm[n]; j++) for(int i = 1; i + (1<<j) - 1 <= n; i++) dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]? dp[i][j-1]:dp[i+(1<<(j-1))][j-1]; } int query(int a,int b) { if(a > b)swap(a,b); int k = mm[b-a+1]; return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]? dp[a][k]:dp[b-(1<<k)+1][k]; } }; struct E { int to,next; } edge[maxn*2]; int tot,head[maxn]; int F[maxn*2]; int P[maxn]; int cnt; //F表示dfs的序列 //P[i]表示i第一次出现的位置 ST st; void init() //初始化 { Tot = tot = 0; memset(head,-1,sizeof(head)); } void dfs(int u,int pre,int dep) { F[++cnt] = u; rmq[cnt] = dep; P[u] = cnt; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == pre)continue; dfs(v,u,dep+1); F[++cnt] = u; rmq[cnt] = dep; } } void ini_lca(int root,int num) { cnt = 0; dfs(root,root,0); st.ini(2*num-1); } void addedge(int u,int v) { edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } int query_lca(int u,int v) { return F[st.query(P[u],P[v])]; } void dfs_build(int u,int pre) { int pos = Hash(a[u]); T[u] = update(T[pre],pos,1); for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == pre) continue; dfs_build(v,u); } } int main() { int q; while(scanf("%d%d",&n,&q) == 2) { for(int i = 1; i <= n; i++) scanf("%d",&a[i]); ini_hash(); init(); int u,v,k; for(int i = 1; i < n; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } ini_lca(1,n); T[n+1] = build(1,m); dfs_build(1,n+1); while(q--) { scanf("%d%d%d",&u,&v,&k); printf("%d ",t[query(T[u],T[v],query_lca(u,v),k)]); } } return 0; }