SPOJ - COTCount on a tree (树上路径第K小,树上主席树)

xiaoxiao2021-02-28  83

Count on a tree

  SPOJ - 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 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  题意:给出一颗树,求两结点第k小的数 分析:跟求区间第K大差不多,这次是维护一个树上的信息。 那么结果为 tree[a]+tree[b]-tree[lca(a,b)]-tree[father[lca(a,b)]] 因为lca结点需要保留,所以是减去父亲结点(这里的father是父亲不是祖先) AC代码: #include<stdio.h> #include<string.h> #include<algorithm> #include<vector> #include<math.h> using namespace std; const int maxn=100500; struct zxtree { int num,lson,rson; }tree[maxn<<5]; struct edge { int u,v; edge(){} edge(int uu,int vv) { u=uu,v=vv; } }; vector<edge>G; vector<int>v[maxn]; int root[maxn]; int val[maxn],hash1[maxn]; int cnt; int father[maxn][40],fa[maxn],maxdeep,deep[maxn]; void addedge(int a,int b) { G.push_back(edge(a,b)); G.push_back(edge(b,a)); int m=G.size(); v[a].push_back(m-2); v[b].push_back(m-1); } void bulidzxtree(int &v,int l,int r) { v=++cnt; tree[v].num=0; if(l==r) return; int mid=(l+r)>>1; bulidzxtree(tree[v].lson,l,mid); bulidzxtree(tree[v].rson,mid+1,r); } int Binary_search(int *p,int x,int r) { int l=1; while(l<=r) { int mid=(l+r)>>1; if(p[mid]<x) l=mid+1; else r=mid-1; } return l; } void init(int n) { memset(root,0,sizeof(root)); memset(father,0,sizeof(father)); memset(fa,0,sizeof(fa)); memset(deep,0,sizeof(deep)); maxdeep=log(n*1.0)/log(2.0); for(int i=0;i<=n;i++) v[i].clear(); G.clear(); } void update(int p,int &v,int l,int r,int x) { v=++cnt; tree[v]=tree[p]; tree[v].num++; if(l==r) return; int mid=(l+r)>>1; if(x>mid) update(tree[p].rson,tree[v].rson,mid+1,r,x); else update(tree[p].lson,tree[v].lson,l,mid,x); } void dfs(int rt,int t) { update(root[fa[rt]],root[rt],1,t,val[rt]); for(int i=1;i<=maxdeep;i++) { father[rt][i]=father[father[rt][i-1]][i-1]; if(father[rt][i]==0) break; } for(int i=0;i<v[rt].size();i++) { edge &e=G[v[rt][i]]; if(father[rt][0]!=e.v) { father[e.v][0]=rt; fa[e.v]=rt; deep[e.v]=deep[rt]+1; dfs(e.v,t); } } } int lca(int a,int b) { if(deep[a]>deep[b]) swap(a,b); for(int i=maxdeep;i>=0;i--) { if(deep[a]<deep[b]&&deep[a]<=deep[father[b][i]]) { b=father[b][i]; } } if(a==b) return a; for(int i=maxdeep;i>=0;i--) { if(father[a][i]!=father[b][i]) { a=father[a][i]; b=father[b][i]; } } if(a!=b) a=father[a][0]; return a; } int query(int a,int b,int lc,int ff,int l,int r,int k) { if(l==r) return l; int mid=(l+r)>>1; int ans=tree[tree[a].lson].num+tree[tree[b].lson].num-tree[tree[lc].lson].num-tree[tree[ff].lson].num; //printf("! %d\n",ans); if(k<=ans) query(tree[a].lson,tree[b].lson,tree[lc].lson,tree[ff].lson,l,mid,k); else query(tree[a].rson,tree[b].rson,tree[lc].rson,tree[ff].rson,mid+1,r,k-ans); } int main() { int n,m; while(scanf("%d%d",&n,&m)==2) { init(n); cnt=0; for(int i=1;i<=n;i++) { scanf("%d",&val[i]); hash1[i]=val[i]; } sort(hash1+1,hash1+n+1); int t=unique(hash1+1,hash1+1+n)-hash1-1; for(int i=1;i<=n;i++) { val[i]=Binary_search(hash1,val[i],t); //val[i]=lower_bound(hash+1,hash+t+1,val[i])-hash; } bulidzxtree(root[0],1,t); int rt; for(int i=0;i<n-1;i++) { int a,b; scanf("%d%d",&a,&b); father[b][0]=a; addedge(a,b); if(!father[a][0]) rt=a; } deep[rt]=1; dfs(rt,t); for(int i=0;i<m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); int lc=lca(a,b); int s=query(root[a],root[b],root[lc],root[fa[lc]],1,t,c); printf("%d\n",hash1[s]); } } }
转载请注明原文地址: https://www.6miu.com/read-60219.html

最新回复(0)