guofuqian50

链接

题目大意

给定一个无向图,每条边有正边权,每个点有点权 wi。有一些点被标记。假设某一天能见度为 ri,那么定义一个点 u 的危险度就是 [ v被标记 ] [ dis(v,u)ri ]

如果一个点的危险度小于它的点权,那么称这个点是安全的。

接下来有 n 天,第 i 天能见度为 ri。对于每个点,输出有多少天该点事安全的。

题解

看似条件有很多,其实可以发现对于一个点 i,只要第 t 天的能见度 rt 小于离 iwi 近的标记点到 i 的最短距离,那么它就是安全的。

所以我们只要找到距离 iwi 近的点即可。

考虑如果 wi=1,我们只需要把每个标记点压入优先队列,跑一边最短路即可。

可以发现这道题中 wi20,考虑在转移中加上一维,即该点是以哪一个点 u 为起点转移过来的。如果该点已经 u 被转移过了那么直接跳过。

显然,如果一个点 i 已经被20个不同的起点转移到了,那么显然之后转移到它的其他点不会成为离 iwi 近的点,也不会对 i 之后的点产生贡献,直接跳过即可。

可以发现,这种情况下一个点只会被压入优先队列至多 20 次,时间复杂度 O(w×mlogn)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<map>
#define N 100010
#define M 200010
#define ll long long
using namespace std;
int nxt[M<<1],to[M<<1],head[N],cnt;
ll w[M<<1];
void add(int u,int v,ll w1)
{
	nxt[++cnt]=head[u];
	to[cnt]=v;
	w[cnt]=w1;
	head[u]=cnt;
}
map<int,ll>dis[N];
struct node{
	ll a;
	int s,u;
	node(int S=0,int U=0,ll A=0):a(A),s(S),u(U){}
	bool operator <(const node b)const{return a>b.a;}
};
priority_queue<node>q;
bool in[N],sp[N];
int tot,n,m;
struct pnode{
	int x;
	ll v;
	bool operator <(const pnode a)const{return v<a.v;}
}swp[23];
int kth[N];
ll kth_dis[N];
void dij()
{
	for(int i=1;i<=n;i++)
	if(sp[i]) q.push(node(i,i,0));
	while(!q.empty())
	{
		node p=q.top();
		q.pop();
		int u=p.u;
		if(dis[u].count(p.s)) continue;
		if(dis[u].size()>20) continue;
		dis[u][p.s]=p.a;
		for(int i=head[u];i;i=nxt[i])
		{
			int v=to[i];
			if(dis[v].count(p.s)) continue;
			q.push((node){p.s,v,p.a+w[i]});
		}
	}
	for(int i=1;i<=n;i++)
	{
		tot=0;
		for(auto u:dis[i]) swp[++tot]=(pnode){u.first,u.second};
		sort(swp+1,swp+tot+1);
		kth_dis[i]=kth[i]>tot?1e18:swp[kth[i]].v;
	}
}
ll num[N];
int ptot;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v;
		ll w;
		scanf("%d%d%lld",&u,&v,&w);
		add(u,v,w);
		add(v,u,w);
	}
	int k;
	scanf("%d",&k);
	for(int i=1,a;i<=k;i++) scanf("%d",&a),sp[a]=true;
	for(int i=1;i<=n;i++) scanf("%d",&kth[i]);
	dij();
	scanf("%d",&ptot);
	for(int i=1;i<=ptot;i++) scanf("%lld",&num[i]);
	sort(num+1,num+ptot+1);
	for(int i=1;i<=n;i++) printf("%lld ",lower_bound(num+1,num+ptot+1,kth_dis[i])-num-1);
	return 0;
}
posted @   Flying2018  阅读(149)  评论(2编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示