[CF1483D] Useful Edges

前言

如果你毫无思路,考虑暴力!然后优化它!

题目

CF

洛谷

讲解

如果你想容斥,那么你已经没救了。

\(\tt Floyd\) 应该不用讲吧。

我们先想暴力,枚举一条边,然后在三元组里面检验,时间复杂度是 \(O(mq)=O(n^4)\)

我们发现枚举边似乎不是很能优化,于是我们考虑是否能够不枚举三元组。

我们把一条边是好边的条件写下来:存在一个三元组 \(l_{i,j}\ge dis_{i,u}+w_{u,v}+dis_{v,j}\)

移项: \(l_{i,j}-dis_{i,u}\ge w_{u,v}+dis_{v,j}\)

我们发现 \(RHS\) 已经和 \(i\) 无关,可以 \(O(nm)\) 做,这时我们只需要知道 \(LHS\) 即可。

\(LHS\) 最大值为 \(MAX_{j,u}\),显然可以用 \(O(qn)\) 的时间复杂度预处理,注意一个三元组中的 \(l\) 既可以代表 \(l_{i,j}\) 也可以代表 \(l_{j,i}\)

此时时间复杂度已经降为了 \(O(n^3)\) 级别。

代码

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read();
	for(int i = 1;i <= n;++ i) 
		for(int j = 1;j <= n;++ j)
			if(i ^ j) dis[i][j] = INF;
	for(int i = 1;i <= m;++ i)
	{
		u[i] = Read(),v[i] = Read(),w[i] = Read();
		dis[u[i]][v[i]] = dis[v[i]][u[i]] = w[i];
	}
	for(int k = 1;k <= n;++ k)
		for(int i = 1;i <= n;++ i)
			for(int j = 1;j <= n;++ j)
				dis[i][j] = Min(dis[i][j],dis[i][k]+dis[k][j]);
	for(int Q = Read(); Q ;-- Q)
	{
		int i = Read(),j = Read(),l = Read();
		for(int u = 1;u <= n;++ u) MAX[j][u] = Max(MAX[j][u],l-dis[i][u]),MAX[i][u] = Max(MAX[i][u],l-dis[j][u]);
	}
	for(int i = 1;i <= m;++ i)
		for(int j = 1;j <= n;++ j)
			if(MAX[j][u[i]] >= w[i]+dis[v[i]][j])
			{
				ans++;
				break;
			}
	Put(ans);
	return 0;
}
posted @ 2021-05-27 15:59  皮皮刘  阅读(47)  评论(0编辑  收藏  举报