NHOI 2023 Feb T6 拯救地球

题意

地球上有 n 个国家,有 m 条无向道路,每条道路上只有一个外星生物(地球上的外星生物全部都在道路上,国家里面没有外星生物),每个外星生物都有一个防御值,接着你有 q 次任务,每次任务你拥有 w 的攻击力(每次任务的攻击力是一直不变的),然后用传送门将你送去国家 x(国家 x 已经被你拯救),你的任务就是拯救尽可能多的国家。(如果国家 a 与国家 b 之间有一条道路,国家 a 已经被你拯救,并且你的攻击值大于等于这条道路上外星生物的防御值,那么国家 b 能被你拯救,否则你无法通过这条道路拯救国家 b

对于每次任务,输出你最多能拯救的国家数目,每次任务独立,互不影响。

Step1:

直接暴力建图,暴力计算答案。

于是时间复杂度就为 O(qm)

因为很显然并不是正解,所以就没打了。

Step2:

不难发现,如果从 a 开始可以拯救到 b,那么再相同的情况下从 b 也能到 a。既然如此,所有点都能到达在同一连通块的任一点了,而答案正是这个连通块的点的数量。两个点连一条边,就是将两点所对应的这两个连通块合并。

既然如此,我们可以用并查集来维护这个合并了。

显然如果一条边的边权 ew,给定的战斗力为 qw,那么必须要满足 ewqw 才能连这条边。注意到询问中的 w 并不是升序的,可以使用离线来让他变成升序。并且所有边都是按照 w 来排序的,这样就可以不需要有删边的操作了。

于是,这个代码很轻松的就出来了。

注意一点,这里可以直接存 u,v,w ,而不是真正的建图。因为在这里,建一条边实质只是把两个连通块合并而已。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,M=4e5+5,Q=2e5+5;
int n,m,q,p;
struct edge{int u,v,w;}e[M];
bool cmp(edge x,edge y){return x.w<y.w;}
struct data{int b,id,w,ans;}que[Q];
bool cmpw(data x,data y){return x.w<y.w;}
bool cmpid(data x,data y){return x.id<y.id;}
int fa[N],num[N];
int find(int x){return (x==fa[x]?x:fa[x]=find(fa[x]));}
void merge(int u,int v)
{
	u=find(u);v=find(v);
	if(u==v)return;
	fa[v]=u;
	num[u]+=num[v];
}
void solve(int lim)
{
	while(1)
	{
		p++;
		if(p>m)break;
		if(e[p].w<=lim)merge(e[p].u,e[p].v);
		else break;
	}
	p--;
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)fa[i]=i,num[i]=1;
	for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	sort(e+1,e+1+m,cmp);
	for(int i=1;i<=q;i++)scanf("%d%d",&que[i].b,&que[i].w),que[i].id=i;
	sort(que+1,que+1+q,cmpw);
	for(int i=1;i<=q;i++)
	{
		solve(que[i].w);
		que[i].ans=num[find(que[i].b)];
	}
	sort(que+1,que+1+q,cmpid);
	for(int i=1;i<=q;i++)printf("%d\n",que[i].ans);
	return 0;
}
posted @   大眼仔Happy  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示