E. Hammer to Fall题解

E. Hammer to Fall

可以想到处理每个点,每个人走的路线都是固定的,所以可以 \(dp_{i,j}\) 预处理在 \(i\) 时间开始初始在 \(x\) 点所需要的代价。

第一维可以通过倒叙转移来省掉。

则显然易见枚举所有出边中最小的 \(dp_y+w\)转移过来,但是复杂度 \(O(nq)\) 太大。

那对于度数大的点一个个枚举太慢,所有可以维护一个 multiset 来动态维护最小值。

还有一种考虑方法是根号分治,对于度数小于 \(blo\) 的点,直接暴力枚举即可,对于度数大于 \(blo\) 的点,对于时间分块,每过 \(blo\) 个时间点,对全局更新,因为 \(blo\) 个点最多修改 \(blo\) 个点,所以直接nth_element找到前 \(blo\) 小的 \(dp_y+w\)

意思是并不需要枚举所有点来转移,只要找到前 \(blo\) 小的点转移。

#include<bits/stdc++.h>
#define ll long long
#define int ll
#define ls p<<1
#define rs p<<1|1
#define re register 
#define pb push_back
#define pir pair<int,int> 
#define f(a,x,i) for(int i=a;i<=x;i++)
#define fr(a,x,i) for(int i=a;i>=x;i--)
#define fi first
#define se second
#define lowbit(x) (x&-x)
using namespace std;
const int N=4e6+10;
const int M=5e6+10;
const int mod=998244353;
const int INF=1e18+7;
mt19937 rnd(251);

int n,m,q; 

int people[N];

vector<pair<int,int>> g[N];

int v[N];

int boom[N];

int f[N];

vector<int> spe;

bool cmp(pair<int,int> g,pair<int,int> h){
	return f[g.fi]+g.se<f[h.fi]+h.se;
}

void solve(){
	cin>>n>>m>>q;
	int len=sqrt(m);
	for(int i=1;i<=n;i++){
		cin>>people[i];
	}
	
	for(int i=1;i<=m;i++){
		int x,y,w; 
		cin>>x>>y>>w;
		g[x].push_back({y,w});
		g[y].push_back({x,w});
	}
	
	for(int i=1;i<=n;i++){
		if(g[i].size()>len){
			spe.push_back(i);
		}
	}
	
	for(int i=1;i<=q;i++){
		cin>>boom[i];
	}
	
	for(int j=0;j<spe.size();j++){
		int u=spe[j];
		nth_element(g[u].begin(),g[u].begin()+len,g[u].end(),cmp);
	}
	
	for(int i=q;i>=1;i--){
		int x=boom[i];
		int mi=INF;
		for(int j=0;j<min((ll)g[x].size(),len);j++){
			int y=g[x][j].fi;
			int w=g[x][j].se;
			mi=min(mi,f[y]+w);	
		}	
		f[x]=mi;
		if(i==1||i%len==0){
			for(int j=0;j<spe.size();j++){
				int u=spe[j];
				nth_element(g[u].begin(),g[u].begin()+len,g[u].end(),cmp);
			}
		}
	}
	
	int ans=0;
	for(int i=1;i<=n;i++){
		ans+=(f[i]%mod*people[i]%mod)%mod;
		ans%=mod; 
	}
	cout<<ans<<'\n';
} 



signed main(){
//  	freopen("kingdom3.in","r",stdin);
//  	freopen("a.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(nullptr);   
    int t=1;
//	cin>>t;
	while(t--){
		solve();
	} 
    return 0;
}
posted @ 2025-11-18 09:48  sad_lin  阅读(3)  评论(0)    收藏  举报