【BZOJ2750】【HAOI2012】道路(最短路+拓撲)
阿新 • • 發佈:2018-12-30
容易想到列舉所有起點 做最短路 然後列舉邊統計次數
一條邊(x,y)的貢獻 肯定是 s到x最短路的方案數 乘上 s到其他點但經過了y的最短路
對於前者
每個點可以從前一個點遞推過來 只要滿足dis[vis]==dis[now]+edge[u].val 當一個點被所有入邊都統計了一次後 就可以搜他了(拓撲思想)
對於後者
每個點從後一個點遞推過來
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define N 5505 #define M 5005 #define ll long long using namespace std; const int mod=1000000007; template <class T> inline void read(T &x) { x=0; static char ch=getchar(); while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); } int n,m,first[N],tot,dis[N]; ll a[N],b[N],ans[N]; struct Edge { int from,to,next,val; }edge[M]; inline void addedge(int x,int y,int z) { tot++; edge[tot].from=x; edge[tot].to=y; edge[tot].next=first[x]; edge[tot].val=z; first[x]=tot; } bool visit[N],onroad[N]; typedef pair<int,int> Pair; void Dijkstra(int s) { priority_queue<Pair,vector<Pair>,greater<Pair> > heap; memset(dis,0x3f,sizeof(dis)); memset(visit,false,sizeof(visit)); heap.push(make_pair(0,s)); dis[s]=0; while(!heap.empty()) { int now=heap.top().second; heap.pop(); if(visit[now]) continue; visit[now]=true; for(int u=first[now];u;u=edge[u].next) { int v=edge[u].to; if(dis[now]+edge[u].val<dis[v]) { dis[v]=dis[now]+edge[u].val; heap.push(make_pair(dis[v],v)); } } } } int in[N]; void dfs1(int now) { visit[now]=true; for(int u=first[now];u;u=edge[u].next) { int vis=edge[u].to; if(dis[vis]==dis[now]+edge[u].val) //說明在最短路上 { in[vis]++; if(visit[vis]) continue; dfs1(vis); } } } void dfs2(int now) { for(int u=first[now];u;u=edge[u].next) { int vis=edge[u].to; if(dis[vis]==dis[now]+edge[u].val) { onroad[u]=true; a[vis]=(a[vis]+a[now])%mod; in[vis]--; if(in[vis]==0) dfs2(vis); } } } void dfs3(int now) { b[now]=1; for(int u=first[now];u;u=edge[u].next) { int vis=edge[u].to; if(dis[now]+edge[u].val==dis[vis]) { if(!b[vis]) dfs3(vis); //最短路沒有環 放心dfs b[now]=(b[now]+b[vis])%mod; } } } void Init() { memset(onroad,false,sizeof(onroad)); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(in,0,sizeof(in)); } int main() { read(n),read(m); for(int i=1,x,y,z;i<=m;i++) { read(x),read(y),read(z); addedge(x,y,z); } for(int i=1;i<=n;i++) { Init(); Dijkstra(i); memset(visit,0,sizeof(visit)); dfs1(i); //來自最短路上的入度 a[i]=1; dfs2(i); //i到每個點最短路的方案數 dfs3(i); //i製造的最短路經過每個點的數量 for(int j=1;j<=m;j++) if(onroad[j]) ans[j]=(ans[j]+a[edge[j].from]*b[edge[j].to]%mod)%mod; } for(int i=1;i<=m;i++) cout<<ans[i]<<'\n'; return 0; }