版权声明:欢迎转载!请注明出处!qwq https://blog.csdn.net/g21glf/article/details/86655489
传送门
【题目分析】
这不就是星球大战吗。。。。。。
题干很长,但就一句话:定义两点之间的距离为路径最小值,多组询问v,k,求与v距离>=k的点的个数
先将所有询问离线,因为对于同一个点的k对应的答案是单调递减的,所以将所有询问按k从大到小排序,所有边按边权从大到小排序,然后根据k一条一条往里面丢边。
每次丢完不小于k的边后直接查v所在联通块的大小即可。(要减去自己)
【代码~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int MAXM=2e5+10;
const int INF=0x3f3f3f3f;
int n,cnt,q;
int fa[MAXN],siz[MAXN];
int ans[MAXN];
struct Edge{
int u,v,w;
friend inline bool operator<(const Edge &a,const Edge &b){
return a.w>b.w;
}
}edge[MAXN];
struct Query{
int v,k,id;
friend inline bool operator<(const Query &a,const Query &b){
return a.k>b.k;
}
}query[MAXN];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
int find(int x){
if(x==fa[x])
return x;
return fa[x]=find(fa[x]);
}
void merge(int x,int y){
fa[x]=y;
siz[y]+=siz[x];
}
int main(){
n=Read(),q=Read();
for(int i=1;i<=n;++i)
fa[i]=i,siz[i]=1;
for(int i=1;i<n;++i){
edge[i].u=Read(),edge[i].v=Read(),edge[i].w=Read();
}
sort(edge+1,edge+n);
for(int i=1;i<=q;++i){
query[i].k=Read(),query[i].v=Read();
query[i].id=i;
}
sort(query+1,query+q+1);
int p=1;
for(int i=1;i<=q;++i){
while(edge[p].w>=query[i].k&&p<n){
int x=find(edge[p].u),y=find(edge[p].v);
if(x!=y)
merge(x,y);
p++;
}
ans[query[i].id]=siz[find(query[i].v)]-1;
}
for(int i=1;i<=q;++i)
cout<<ans[i]<<'\n';
return 0;
}