题解:AT_abc307_f [ABC307F] Virus 2

思路

考虑模拟传染过程,对于每一个已经被感染的点(下文称为当前点),遍历其能到达的点(下文称为新点),记这条边的边权为 \(w\),分为以下两步:

  1. 判断新点能否和当前点在同一天内被感染;

  2. 若不能,则从当前点被感染的天数(记为 \(t\))向后找,找到最小的 \(i\) 使得 \(i > t\) 且 \(X_i \ge w\),\(i\) 即为新点被感染的时间。

对于第一种情况,可以把上一天被感染的点看做起点跑最短路,若新点的 \(dis\) 小于等于 \(X_t\),则可以在同一天内被感染。

对于第二种情况,显然暴力查找会超时,考虑二分,每次二分时检查数组 \(X\) 在区间 \([l,mid]\) 的最大值,若该值大于等于 \(w\) 则说明答案在区间 \([l,mid]\) 中,否则在区间 \([mid+1,r]\) 中。使用 ST 表维护静态区间最大值即可。

注意处理时先处理更早被感染的点,以及每个点只能入队一次,保证复杂度正确。

代码

#include<bits/stdc++.h>
#define int long long
#define MAXN 1000005
#define pi pair<int,pair<int,int> >
#define mk make_pair
#define lson root<<1
#define rson root<<1|1
using namespace std;
const int inf=1e18;
int n,m,k,cnt,head[MAXN],d,ans[MAXN],a[MAXN],t[MAXN],dis[MAXN],maxn[MAXN][25],lg[MAXN],vis[MAXN];
void build(){
	lg[1]=0;
	for(int i=2;i<=d;i++){
		lg[i]=lg[i>>1]+1;
	}
	for(int i=1;i<=d;i++)maxn[i][0]=t[i];
	for(int i=1;i<=23;i++){
		for(int j=1;j+(1<<i)<=d+1;j++){
			maxn[j][i]=max(maxn[j][i-1],maxn[j+(1<<(i-1))][i-1]);
		}
	}
}
int query(int l,int r){
	int tmp=lg[r-l+1];
	return max(maxn[l][tmp],maxn[r-(1<<tmp)+1][tmp]);
}
int check(int w,int l){
	int r=d,mid,tans=inf;
	if(l>r)return inf;
	while(l<=r){
		mid=(l+r)>>1;
		if(query(l,mid)>=w){
			tans=mid;
			r=mid-1;
		}else{
			l=mid+1;
		}
	}
	return tans;
}
struct Edge{
	int value,next,w;
}edge[MAXN];
void addedge(int u,int v,int w){
	edge[++cnt].value=v;
	edge[cnt].next=head[u];
	edge[cnt].w=w;
	head[u]=cnt;
}
void bfs(){
	priority_queue<pi,vector<pi>,greater<pi> >q;
	for(int i=1;i<=k;i++)ans[a[i]]=0,dis[a[i]]=0,q.push(mk(0,mk(0,a[i])));
	while(!q.empty()){
		int tmp=q.top().first,x=q.top().second.second;q.pop();
		if(vis[x])continue;
		vis[x]=1;
		for(int i=head[x];i;i=edge[i].next){
			int y=edge[i].value,w=edge[i].w;
			if(ans[y]>tmp&&dis[x]+w<=t[tmp]){
				ans[y]=tmp;
				dis[y]=dis[x]+w;
				q.push(mk(tmp,mk(dis[y],y)));
			}else if(ans[y]==tmp&&dis[x]+w<dis[y]){
				dis[y]=dis[x]+w;
				q.push(mk(tmp,mk(dis[y],y)));
			}else{
				int ntmp=check(w,tmp+1);
				if(ntmp==inf)continue;
				if(ntmp<ans[y]){
					ans[y]=ntmp;
					dis[y]=w;
					q.push(mk(ntmp,mk(dis[y],y)));
				}else if(ntmp==ans[y]&&w<dis[y]){
					dis[y]=w;
					q.push(mk(ntmp,mk(dis[y],y)));
				}
			}
		}
	}
}
inline int read(){
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
signed main(){
//	freopen("virus.in","r",stdin);
//	freopen("virus.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u,v,w;u=read(),v=read(),w=read();
		addedge(u,v,w),addedge(v,u,w);
	}
	k=read();
	for(int i=1;i<=k;i++)a[i]=read();
	d=read();
	for(int i=1;i<=d;i++)t[i]=read();
	t[0]=-inf;
	for(int i=1;i<=n;i++)ans[i]=inf,dis[i]=inf;
	build();
	bfs();
	for(int i=1;i<=n;i++)printf("%lld\n",ans[i]==inf?-1:ans[i]);
	return 0;
}

posted @ 2025-11-02 22:12  CharlieCai2024  阅读(25)  评论(0)    收藏  举报