题意

给定一张 $n$ 个点, $m$ 条边的无向图,有点权 $p_i$ ,边权 $q_i$ 。生成树的权值为

$$\sum_{e\in E}q_e\sum_{u\in\text{inaccessible}(e)}p_u $$

其中 $\text{inaccessible}(e)$ 表示从生成树中删除 $e$ 后,从 $1$ 出发不能到达的结点集合。

求可能的最小权值。

思路

发现从边出发考虑生成树会有瓶颈:选的边并不确定、不知道可以到达边的哪头、点集受树的形态制约。由于每个点都要选(都确定),我们不妨考虑先从点考虑,把式子转化为

$$\sum_{u\in V}p_u\sum_{e\in \text{path}(1\rightarrow u)}q_e $$

豁然开朗,里面的和式正好是从 $1$ $u$ 的距离,显然最短路是最优的。

代码

const int N = 1e5 + 5;

inline ll read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n, m;
	int p[N];
	ll dis[N];
	typedef pair<ll, int> P;
	vector<P> e[N];
	priority_queue <P, vector<P>, greater<P> > q;
	void dijkstra() {
		memset(dis, 0x3f, sizeof dis); dis[1] = 0;
		q.emplace(0ll, 1);
		for (int u; !q.empty(); ) {
			P x = q.top(); q.pop();
			if (dis[u = x.second] < x.first) continue;
			for (auto [w, v] : e[u]) 
				if (dis[u] + w <= dis[v]) 
					q.emplace(dis[v] = dis[u] + w, v);
		}
	} 
	int main () {
		n = read(), m = read();
		for (int i = 1; i <= n; ++i) p[i] = read();
		for (int i = 1; i <= m; ++i) {
			int u = read(), v = read(); ll w = read();
			e[u].emplace_back(w, v);
			e[v].emplace_back(w, u);
		}
		
		dijkstra();
		
		ll ans = 0;
		for (int i = 1; i <= n; i++) ans += dis[i] * p[i];
		printf ("%lld\n", ans);
		return 0;
	}
}

int main () {
	string str = "";
//	freopen((str + ".in").c_str(), "r", stdin);
//	freopen((str + ".out").c_str(), "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2025-09-13 16:39:24
博客类型
标签