【题目描述】
在业余时间,Farmer John创建了一个新的视频共享服务,他将其命名为MooTube。在MooTube上,Farmer John的奶牛可以录制,分享和发现许多有趣的视频。他的奶牛已经发布了 $N$ 个视频 ( $1 leq N leq 100,000 $),为了方便将其编号为 $1 ldots N$ 。然而,FJ无法弄清楚如何帮助他的奶牛找到他们可能喜欢的新视频。
FJ希望为每个MooTube视频创建一个“推荐视频”列表。这样,奶牛将被推荐与他们已经观看过的视频最相关的视频。
FJ设计了一个“相关性”度量标准,顾名思义,它确定了两个视频相互之间的相关性。他选择 $N-1$ 对视频并手动计算其之间的相关性。然后,FJ将他的视频建成一棵树,其中每个视频是节点,并且他手动将 $N-1$ 对视频连接。为了方便,FJ选择了 $N-1$ 对,这样任意视频都可以通过一条连通路径到达任意其他视频。 FJ决定将任意一对视频的相关性定义为沿此路径的任何连接的最小相关性。
Farmer John想要选择一个 $K$ 值,以便在任何给定的MooTube视频旁边,推荐所有其他与该视频至少有 $K$ 相关的视频。然而,FJ担心会向他的奶牛推荐太多的视频,这可能会分散他们对产奶的注意力!因此,他想设定适当的 $K$ 值。 Farmer John希望得到您的帮助,回答有关 $K$ 值的推荐视频的一些问题。
【输入格式】
第一行输入包含 $N$ 和 $Q$ ( $1 leq Q leq 100,000$)。
接下来的 $N-1$ 行描述了FJ手动比较的一对视频。
每行包括三个整数 $p_i,q_i$和 $r_i (1 leq p_i, q_i leq N, 1 leq r_i leq 1,000,000,000 $),表示视频 $p_i$和 $q_i$ 已连接并且相关性为 $r_i$。
接下来的 $Q$ 行描述了Farmer John的第 $Q$ 个问题。
每行包含两个整数, $k_i$ 和 $v_i$ ($1 leq k_i leq 1,000,000,000, 1 leq v_i leq N $),表示FJ的第 $i$ 个问题询问中当 $K = k_i$ 时,第 $v_i$个视频推荐列表中将推荐的视频数。
【输出格式】
输出 $Q$ 行。 在第 $i$ 行,输出FJ的第 $i$ 个问题的答案。
【样例】
样例输入
4 3
1 2 3
2 3 2
2 4 4
1 2
4 1
3 1
样例输出
3
0
2
【题解】
将所有边与询问从大到小排序,并查集维护即可。遇到边则合并并查集,遇到询问查询并查集大小。
【代码】
#include<bits/stdc++.h> struct state { int u,v,w,op; } A[200010]; int n,q,ans[100010],f[100010],siz[100010],tot; inline int read ( void ) { int x=0;char ch; while ( !isdigit(ch=getchar()) ) ; for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48); return x; } inline int find ( int x ) { return f[x]==x ? x : f[x]=find(f[x]); } signed main() { n=read();q=read(); for ( int i=1;i<=n;i++ ) f[i]=i,siz[i]=1; for ( int i=1,u,v,w;i<n;i++ ) u=read(),v=read(),w=read(),A[++tot]=(state){u,v,w,0}; for ( int i=1,k,x;i<=q;i++ ) k=read(),x=read(),A[++tot]=(state){x,i,k,1}; std::sort(A+1,A+tot+1,[&](const state &p1,const state &p2){return p1.w==p2.w ? p1.op<p2.op : p1.w>p2.w;}); for ( int i=1;i<=tot;i++ ) if ( A[i].op ) ans[A[i].v]=siz[find(A[i].u)]-1; else { int fu=find(A[i].u),fv=find(A[i].v); if ( fu!=fv ) f[fv]=fu,siz[fu]+=siz[fv]; } for ( int i=1;i<=q;i++ ) printf("%d ",ans[i]); return 0; }