[CF1483D] Useful Edges
前言
如果你毫无思路,考虑暴力!然后优化它!
题目
讲解
如果你想容斥,那么你已经没救了。
\(\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;
}