题意:在顺利攻破Lord lsp的防线之后,lqr一行人来到了Lord lsp的城堡下方。Lord lsp黑化之后虽然拥有了强大的超能力,能够用意念力制造建筑物,但是智商水平却没怎么增加。现在lqr已经搞清楚黑暗城堡有 NN 个房间, MM 条可以制造的双向通道,以及每条通道的长度。lqr深知Lord lsp的想法,为了避免每次都要琢磨两个房间之间的最短路径,Lord lsp一定会把城堡修建成树形的。但是,为了尽量提高自己的移动效率,Lord lsp一定会使得城堡满足下面的条件:设 D[i]D[i] 为如果所有的通道都被修建,第 ii 号房间与第 11 号房间的最短路径长度;而 S[i]S[i] 为实际修建的树形城堡第 ii 号房间与第 11 号房间的路径长度;要求对于所有整数 ii,有 S[i]=D[i]S[i]=D[i] 成立。为了打败Lord lsp,lqr想知道有多少种不同的城堡修建方案。你需要输出答案对 23112^{31}-1 取模之后的结果。

经典的最短路径生成树问题。

我们先用 DijkstraDijkstra 求出 11 号节点到其余节点的单源最短路径,若 xxyy 的父节点,xxyy 之间的路径长度为 numnum,那么 dis[y]=dis[x]+numdis[y]=dis[x]+num

我们把所有节点按照 disdis 值排序,从小到大类似于 PrimPrim ,考虑把每个节点 pp 加入树中有多少个方法,设我们维护的生成树记作 TT,统计有多少个节点 xx 满足 xTx\in Tdis[p]=dis[x]+edge(x,p)dis[p]=dis[x]+edge(x,p),此时让 pp 与任意一个 xx 相连都符合要求。

于是我们直接统计 xx 的数量,根据乘法原理直接相乘即可。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cmath>
#include<algorithm>
#define mod 2147483647
using namespace std;
int n,m;
int head[1001010],cnt;
int s[1010];
int dis[1010],vis[1010];
struct node
{
	int next;
	int to;
	int num;
}e[1001010];
void add(int from,int to,int num)
{
	e[++cnt].next=head[from];
	e[cnt].to=to;
	e[cnt].num=num;
	head[from]=cnt;
}
void dijkstra()
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[1]=0;
	priority_queue< pair<int,int> > q;
	q.push(make_pair(0,1));
	while(!q.empty())
	{
		int u=q.top().second;
		q.pop();
		if(vis[u])
			continue;
		vis[u]=1;
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to;
			if(dis[v]>dis[u]+e[i].num)
			{
				dis[v]=dis[u]+e[i].num;
				q.push(make_pair(-dis[v],v));
			}
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);
		add(b,a,c);
	}
	dijkstra();
	for(int i=1;i<=n;i++)
		for(int j=head[i];j;j=e[j].next)
			if(dis[e[j].to]==dis[i]+e[j].num)
				s[e[j].to]++;
	long long ans=1;
	for(int i=1;i<=n;i++)
		if(s[i])
			ans=ans%mod*s[i]%mod;
	printf("%lld",ans);
	return 0;
}