洛谷4185 【USACO18JAN】 MooTube(并查集)

版权声明:欢迎转载!请注明出处!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;
}

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/86655489
今日推荐