1. 程式人生 > >BZOJ5109 CodePlus 2017大吉大利,晚上吃雞!(最短路+拓撲排序+bitset)

BZOJ5109 CodePlus 2017大吉大利,晚上吃雞!(最短路+拓撲排序+bitset)

  首先跑正反兩遍dij求由起點/終點到某點的最短路條數,這樣條件一就轉化為f(S,A)*f(T,A)+f(S,B)*f(T,B)=f(S,T)。同時建出最短路DAG,這樣圖中任何一條S到T的路徑都是最短路徑,對於條件二就只需要判斷A是否能走到B。注意到空間開的非常大。那麼對於條件二的可達性顯然是可以bitset優化的。對於條件一可以map套bitset。兩者and再count一下就可以了。bzoj的空間限制開小了於是這種做法就直接MLE了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include
<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<bitset> using namespace std; #define ll long long #define N 50010 #define P 1000000007 char getc(){char c=getchar();while (c==10||c==13||c==32) c=getchar();return c;} int gcd(int n,int m){return
m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,S,T,t,p[N],f[2][N],g[N]; ll d[2][N]; bool flag[N]; struct data{int
to,nxt,len; }edge[N<<1]; struct data2 { int x;ll d; bool operator <(const data2&a) const { return d>a.d; } }; priority_queue<data2> q; bitset<N> to[N],from[N]; map<int,bitset<N> > cnt; void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;} void inc(int &x,int y){x+=y;if (x>=P) x-=P;} void dijkstra(int S,int op) { memset(d[op],42,sizeof(d[op]));d[op][S]=0;f[op][S]=1; memset(flag,0,sizeof(flag)); while (!q.empty()) q.pop(); q.push((data2){S,0}); for (;;) { while (!q.empty()&&flag[q.top().x]) q.pop(); if (q.empty()) break; data2 x=q.top();q.pop(); flag[x.x]=1; for (int i=p[x.x];i;i=edge[i].nxt) { if (x.d+edge[i].len<d[op][edge[i].to]) { d[op][edge[i].to]=x.d+edge[i].len; q.push((data2){edge[i].to,d[op][edge[i].to]}); f[op][edge[i].to]=0; } if (x.d+edge[i].len==d[op][edge[i].to]) inc(f[op][edge[i].to],f[op][x.x]); } } } namespace shortestpathDAG { int p[N]={0},q[N]={0},degree[N]={0},t=0; struct data{int to,nxt;}edge[N]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void topsort() { for (int i=1;i<=t;i++) degree[edge[i].to]++; int head=0,tail=0;for (int i=1;i<=n;i++) if (!degree[i]) q[++tail]=i; while (tail<n) { int x=q[++head]; for (int i=p[x];i;i=edge[i].nxt) { degree[edge[i].to]--; if (!degree[edge[i].to]) q[++tail]=edge[i].to; } } } void work() { ll ans=0; for (int i=1;i<=n;i++) { int x=q[i];from[x][x]=1; for (int j=p[x];j;j=edge[j].nxt) from[edge[j].to]|=from[x]; } for (int i=n;i>=1;i--) { int x=q[i];to[x][x]=1; for (int j=p[x];j;j=edge[j].nxt) to[x]|=to[edge[j].to]; ans+=((~(to[x]|from[x]))&cnt[(g[T]-g[x]+P)%P]).count(); } cout<<(ans>>1); } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5109.in","r",stdin); freopen("bzoj5109.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(),S=read(),T=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(),z=read(); addedge(x,y,z),addedge(y,x,z); } dijkstra(S,0),dijkstra(T,1); if (f[0][T]==0) {cout<<(1ll*n*(n-1)>>1);return 0;} for (int i=1;i<=n;i++) { if (d[0][i]+d[1][i]==d[0][T]) g[i]=1ll*f[0][i]*f[1][i]%P; cnt[g[i]][i]=1; } for (int i=1;i<=t;i+=2) { if (d[0][edge[i+1].to]+d[1][edge[i].to]+edge[i].len==d[0][T]) shortestpathDAG::addedge(edge[i+1].to,edge[i].to); if (d[0][edge[i].to]+d[1][edge[i+1].to]+edge[i].len==d[0][T]) shortestpathDAG::addedge(edge[i].to,edge[i+1].to); } shortestpathDAG::topsort(); shortestpathDAG::work(); return 0; }