解题:HAOI 2012 道路

题面

这题不开O2怎么过=。=

可能这种有关最短路的计数题做多了就有些感觉了......

以每个点为基准跑出一张最短路图,然后对每个边$(u,v)$统计两个东西。一个$pre[u]$表示到达$u$这个起点的路径条数,一个$nxt[v]$表示从$v$开始的最短路数,然后对每条边来一下乘法原理。

然后是这两个玩意的统计方法,$pre[]$可以在最短路图上跑拓扑排序得出,$nxt[]$可以跑记忆化搜索,这样统计的复杂度是$O(n+m)$的,总复杂度大概$O(nmlog$ $n)$?然而并不能卡过去......

  1 // luogu-judger-enable-o2
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cctype>
  5 #include<cstring>
  6 #include<algorithm>
  7 using namespace std;
  8 const int N=1505,M=5005;
  9 const long long mod=1e9+7;
 10 struct a{int node,dist;};
 11 bool operator < (a x,a y)
 12 {
 13     return x.dist>y.dist;
 14 }
 15 priority_queue<a> hp;
 16 int dis[N],vis[N],pre[N],nxt[N],deg[N],ans[M],que[N];
 17 int p[N],noww[M],from[M],goal[M],val[M];
 18 int n,m,t1,t2,t3,cnt,f,b;
 19 inline int read()
 20 {
 21     int ret=0;
 22     char ch=getchar();
 23     while(!isdigit(ch))
 24         ch=getchar();
 25     while(isdigit(ch))
 26         ret=(ret<<3)+(ret<<1)+(ch^48),ch=getchar();
 27     return ret;
 28 }
 29 void link(int f,int t,int v)
 30 {
 31     noww[++cnt]=p[f],p[f]=cnt;
 32     goal[cnt]=t,val[cnt]=v,from[cnt]=f;
 33 } 
 34 void Dijkstra(int s)
 35 {
 36     register int i; 
 37     memset(vis,0,sizeof vis);
 38     memset(dis,0x3f,sizeof dis);
 39     dis[s]=0,hp.push((a){s,0});
 40     while(!hp.empty())
 41     {
 42         a tt=hp.top(); hp.pop(); int tn=tt.node;
 43         if(vis[tn]) continue ; vis[tn]=true;
 44         for(i=p[tn];i;i=noww[i])
 45             if(dis[goal[i]]>dis[tn]+val[i])
 46             {
 47                 dis[goal[i]]=dis[tn]+val[i];
 48                 hp.push((a){goal[i],dis[goal[i]]});
 49             }
 50     }
 51 }
 52 void getpre(int nde)
 53 {
 54     register int i,j;
 55     for(i=1;i<=n;i++)
 56         for(j=p[i];j;j=noww[j])
 57             if(dis[goal[j]]==dis[i]+val[j]) deg[goal[j]]++;
 58     que[f=b=0]=nde,pre[nde]=1;
 59     while(f<=b)
 60     {
 61         int tn=que[f++];
 62         for(i=p[tn];i;i=noww[i])
 63             if(dis[goal[i]]==dis[tn]+val[i])
 64             {
 65                 pre[goal[i]]+=pre[tn];
 66                 if(!(--deg[goal[i]])) que[++b]=goal[i];
 67             }
 68     }    
 69 }
 70 void getnxt(int nde)
 71 {
 72     nxt[nde]=1;
 73     for(int i=p[nde];i;i=noww[i])
 74         if(dis[goal[i]]==dis[nde]+val[i])
 75         {
 76             if(!nxt[goal[i]]) getnxt(goal[i]);
 77             nxt[nde]+=nxt[goal[i]];
 78         } 
 79 }
 80 int main ()
 81 {
 82     register int i,j;
 83     scanf("%d%d",&n,&m);
 84     for(int i=1;i<=m;i++)
 85         scanf("%d%d%d",&t1,&t2,&t3),link(t1,t2,t3);
 86     for(i=1;i<=n;i++) 
 87     {
 88         Dijkstra(i);
 89         memset(pre,0,sizeof pre);
 90         memset(nxt,0,sizeof nxt);
 91         memset(deg,0,sizeof deg);
 92         getpre(i),getnxt(i);
 93         for(j=1;j<=m;j++)
 94             if(dis[from[j]]+val[j]==dis[goal[j]])
 95                 ans[j]+=1ll*pre[from[j]]*nxt[goal[j]]%mod,ans[j]%=mod;
 96     }
 97     for(i=1;i<=m;i++)
 98         printf("%d
",ans[i]);
 99     return 0;
100 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/9795062.html