SPOJ_10628_Count_on_a_Tree(主席树+Tarjan)
Posted 晴歌。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ_10628_Count_on_a_Tree(主席树+Tarjan)相关的知识,希望对你有一定的参考价值。
描述
http://www.spoj.com/problems/COT/
给出一棵n个节点的树,树上每一个节点有权值.m次询问,求书上u,v路径中第k小的权值.
COT - Count on a tree
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 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
分析
现在是把原来的问题搬到树上去了.首先我们肯定要求lca,新学了Tarjan的离线算法.
每一个点建立到根节点的主席树,这样最后的结果就是u+v-2*lca,如果lca在所要求的区间内,还要再加上lca.(或者u+v-lca-p[lca]).
自己理解一下吧...挺简单的.
1 #include <cstdio> 2 #include <algorithm> 3 #include <vector> 4 using namespace std; 5 6 const int maxn=100000+5; 7 int n,m,cnt,num; 8 int a[maxn],id[maxn],b[maxn],head[maxn],p[maxn],f[maxn],root[maxn]; 9 bool vis[maxn]; 10 struct edge{ 11 int to,next; 12 edge(){} 13 edge(int a,int b):to(a),next(b){} 14 }g[maxn<<1]; 15 struct Qry{ 16 int u,v,k,lca; 17 Qry(){} 18 Qry(int a,int b,int c,int d):u(a),v(b),k(c),lca(d){} 19 }Q[maxn]; 20 struct node{ int l,r,s; }t[maxn*20]; 21 struct qry{ 22 int v,id; 23 qry(){} 24 qry(int a,int b):v(a),id(b){} 25 }; 26 vector <qry> q[maxn]; 27 28 inline int find(int x){ return x==f[x]?x:f[x]=find(f[x]); } 29 void add_edge(int u,int v){ 30 g[++cnt]=edge(v,head[u]); head[u]=cnt; 31 g[++cnt]=edge(u,head[v]); head[v]=cnt; 32 } 33 void update(int l,int r,int &pos,int d){ 34 t[++num]=t[pos]; pos=num; t[pos].s++; 35 if(l==r) return; 36 int mid=l+(r-l)/2; 37 if(d<=mid) update(l,mid,t[pos].l,d); 38 else update(mid+1,r,t[pos].r,d); 39 } 40 bool cmp(int x,int y){ return a[x]<a[y]; } 41 void dfs(int u){ 42 f[u]=u; root[u]=root[p[u]]; update(1,n,root[u],b[u]); 43 for(int i=head[u];i;i=g[i].next){ 44 if(g[i].to!=p[u]){ 45 p[g[i].to]=u; 46 dfs(g[i].to); 47 f[g[i].to]=u; 48 } 49 } 50 vis[u]=true; 51 int size=q[u].size(); 52 for(int i=0;i<size;i++) if(vis[q[u][i].v]) Q[q[u][i].id].lca=find(q[u][i].v); 53 } 54 void init(){ 55 scanf("%d%d",&n,&m); 56 for(int i=1;i<=n;i++) scanf("%d",&a[i]), id[i]=i; 57 sort(id+1,id+n+1,cmp); 58 for(int i=1;i<=n;i++) b[id[i]]=i; 59 for(int i=1;i<n;i++){ 60 int u,v; 61 scanf("%d%d",&u,&v); 62 add_edge(u,v); 63 } 64 for(int i=1;i<=m;i++){ 65 scanf("%d%d%d",&Q[i].u,&Q[i].v,&Q[i].k); 66 q[Q[i].u].push_back(qry(Q[i].v,i)); q[Q[i].v].push_back(qry(Q[i].u,i)); 67 } 68 } 69 int query(int l,int r,int x,int y,int ra,int a,int k){ 70 if(l==r) return l; 71 int mid=l+(r-l)/2; 72 int s=t[t[x].l].s+t[t[y].l].s-2*t[t[ra].l].s; 73 if(b[a]>=l&&b[a]<=mid) s++; 74 if(k<=s) return query(l,mid,t[x].l,t[y].l,t[ra].l,a,k); 75 else return query(mid+1,r,t[x].r,t[y].r,t[ra].r,a,k-s); 76 } 77 void solve(){ 78 dfs(1); 79 for(int i=1;i<=m;i++){ 80 if(Q[i].u==Q[i].v){ printf("%d\\n",a[Q[i].u]); continue; } 81 printf("%d\\n",a[id[query(1,n,root[Q[i].u],root[Q[i].v],root[Q[i].lca],Q[i].lca,Q[i].k)]]); 82 } 83 } 84 int main(){ 85 init(); 86 solve(); 87 return 0; 88 }
以上是关于SPOJ_10628_Count_on_a_Tree(主席树+Tarjan)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2588 Spoj 10628. Count on a tree
SPOJ 10628. SPOJ COT Count on a tree
BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]