CF416E题解

题意:对于所有的 \((u,v)\),询问有多少条边在这两个点的最短路边集之并内。

考虑对于每一个 \(u\) 建立最短路 DAG 图,问题变成询问唯一的度数为 \(0\) 的节点到所有节点路径的并集有多少条边。

倒是很容易想到用 bitset 去做,不过复杂度是 \(O(\frac {n^4} {\omega})\),应该跑不过去。我们注意到这题 \(O(n^3)\) 可过,所以考虑有没有 \(O(n^2)\) 的暴力。

由于枚举点对是 \(O(n^2)\) 的,考虑把边的计数转化到点上。

\(sum[u]\) 表示 \(u\) 的入度,那么 \((u,v)\) 的路径上有多少条边就转化成了路径并集的权值和,此时就可以使用枚举点对做掉了。

题外话:能不能有更快的做法?

我们发现对于 \(u\) 需要枚举的点一定在其的“子树”之内,所以考虑维护一下子树集合。

然后我们发现 bitset 可以胜任这份工作,不过复杂度是 \(O(\frac {n^3} {\omega}+n^3)\)

笔者只想快点儿做掉这道题,而且建图的话代码太长了,所以只写了 Floyd 的暴力。

#include<cstdio>
typedef unsigned uint;
const uint M=505;	
uint n,m,sum[M],a[M][M],d[M][M],ans[M];
inline uint min(const uint&a,const uint&b){
	return a>b?b:a;
}
signed main(){
	register uint i,j,u,v,val;
	scanf("%u%u",&n,&m);
	for(i=1;i<=n;++i){
		for(j=1;j<=n;++j)a[i][j]=a[j][i]=d[i][j]=d[j][i]=0x7fffffff;
		d[i][i]=0;
	}
	for(i=1;i<=m;++i)scanf("%u%u%u",&u,&v,&val),a[u][v]=a[v][u]=d[u][v]=d[v][u]=min(a[u][v],val);
	for(i=1;i<=n;++i){
		for(u=1;u<=n;++u){
			for(v=1;v<=n;++v){
				d[u][v]=min(d[u][v],d[u][i]+d[i][v]);
			}
		}
	}
	for(i=1;i<=n;++i){
		for(u=1;u<=n;++u)sum[u]=ans[u]=0;
		for(u=1;u<=n;++u){
			for(v=1;v<=n;++v){
				if(d[i][u]+a[u][v]==d[i][v])++sum[v];
			}
		}
		for(u=1;u<=n;++u){
			for(v=1;v<=n;++v){
				if(d[i][u]+d[u][v]==d[i][v])ans[v]+=sum[u];
			}
		}
		for(u=i+1;u<=n;++u)printf("%u ",d[i][u]==0x7fffffff?0:ans[u]);
	}
}
posted @ 2022-01-11 13:57  Prean  阅读(25)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};