1. 程式人生 > >bzoj5188: [Usaco2018 Jan]MooTube (離線+並查集)

bzoj5188: [Usaco2018 Jan]MooTube (離線+並查集)

Problem

給定一棵樹,邊有邊權,定義兩點之間距離為兩點路徑上的最小值。 QQ 次詢問,每次詢問 kivik_i、v_i,問從 viv_i 出發到達每個點時,距離大於等於 kik_i 的點有多少個

Solution

將邊權、詢問中的 kik_i 從大到小排序。 每次將邊連起來,並查集合並。 詢問中,與此點聯通的點的個數即為答案

Code

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 100010
int n,m,sz[N],fa[N],ans[N]
; struct node{int x,y,z;}a[N],q[N]; inline bool cmp(node x,node y){return x.z>y.z;} int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) fa[i]=i,sz[i]=1; for(int i=1;i<n;i++) scanf("%d%d%d",&a[
i].x,&a[i].y,&a[i].z); for(int i=1;i<=m;i++) scanf("%d%d",&q[i].z,&q[i].x),q[i].y=i; sort(a+1,a+n,cmp);sort(q+1,q+m+1,cmp); int tmp=1; for(int i=1;i<=m;i++){ while(tmp<n && a[tmp].z>=q[i].z){ int x=find(a[tmp].x),y=find(a[tmp].y)
; if(x!=y) fa[x]=y,sz[y]+=sz[x]; tmp++; } ans[q[i].y]=sz[find(q[i].x)]-1; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }