[BZOJ5109]大吉大利,晚上吃雞!
阿新 • • 發佈:2018-08-22
int 一個點 jks main i++ reat code -o tr1
上查找對應的\(B\)即可。
[BZOJ5109]大吉大利,晚上吃雞!
題目大意:
一張\(n(n\le5\times10^4)\)個點\(m(m\le5\times10^4)\)條邊的無向圖,節點編號為\(1\)到\(n\),邊權為正整數。給定\(S\)和\(T\),顯然從\(S\)到\(T\)的最短路有一種或多種方案。
選擇\(A,B\)兩個點,約定\(A\)點和\(B\)點必須滿足:
- 所有可能路徑中,必定會經過\(A\)點和\(B\)點中的任意一點;
- 所有可能路徑中,不存在一條路徑同時經過\(A\)點和\(B\)點。
求滿足上面兩個條件的\(A,B\)點對有多少個,交換\(A,B\)的順序算相同的方案。
思路:
首先用Dijkstra求出最短路網絡,顯然這是一個DAG。
在DAG上DP求出一個點到\(S/T\)的方案數,將它們相乘即為經過這個點的路徑數,記作\(F(i)\)。我們同樣也可以用bitset
求出經過這個點的路徑上可能經過的點,記作\(S(i)\)。
而題目所求的\(A\)和\(B\)相當於需要滿足以下兩個條件:
- \(F(A)+F(B)=F(T)\);
- \(A\notin F(B)\)且\(B\notin F(A)\)。
顯然枚舉\(A\)和\(B\)會超時,由於\(F(A)+F(B)=F(T)\)。我們可以開一個map<int,bitset>
保存\(F(B)=F(T)-F(A)\)的可能的\(B\)。
此時我們只需要枚舉\(A\),然後在map
源代碼:
#include<cstdio> #include<cctype> #include<vector> #include<bitset> #include<climits> #include<functional> #include<tr1/unordered_map> #include<ext/pb_ds/priority_queue.hpp> inline int getint() { register char ch; while(!isdigit(ch=getchar())); register int x=ch^'0'; while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); return x; } typedef long long int64; const int N=5e4+1,M=5e4; struct Edge2 { int u,v,w; }; Edge2 edge[M]; struct Edge3 { int to,w; }; std::vector<Edge3> e3[N]; inline void add_edge(const int &u,const int &v,const int &w) { e3[u].push_back((Edge3){v,w}); e3[v].push_back((Edge3){u,w}); } bool vis[N]; int n,m,s,t,ind[N],ind2[N],outd[N]; int64 diss[N],dist[N],f[N],g[N],ans; struct Vertex { int id; int64 d; bool operator > (const Vertex &rhs) const { return d>rhs.d; } }; inline void dijkstra(const int &s,int64 dis[]) { static __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q; static __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[N]; for(register int i=1;i<=n;i++) { p[i]=q.push((Vertex){i,dis[i]=i==s?0:LLONG_MAX}); } while(!q.empty()&&q.top().d!=LLONG_MAX) { const int x=q.top().id; q.pop(); for(register unsigned i=0;i<e3[x].size();i++) { const int &y=e3[x][i].to,&w=e3[x][i].w; if(dis[x]+w<dis[y]) { q.modify(p[y],(Vertex){y,dis[y]=dis[x]+w}); } } } q.clear(); } std::vector<int> e[N],e4[N]; inline void add_edge(const int &u,const int &v) { e[u].push_back(v); e4[v].push_back(u); ind[v]++; ind2[v]++; outd[u]++; } std::queue<int> q; std::bitset<N> b[N]; inline void kahn2() { q.push(t); g[t]=1; while(!q.empty()) { const int &x=q.front(); for(register unsigned i=0;i<e4[x].size();i++) { const int &y=e4[x][i]; g[y]+=g[x]; if(!--outd[y]) q.push(y); } q.pop(); } } inline void kahn() { q.push(s); f[s]=1; while(!q.empty()) { const int &x=q.front(); b[x][x]=true; for(register unsigned i=0;i<e[x].size();i++) { const int &y=e[x][i]; b[y]|=b[x]; f[y]+=f[x]; if(!--ind[y]) q.push(y); } q.pop(); } } inline void kahn3() { q.push(s); while(!q.empty()) { const int &x=q.front(); b[0][x]=true; b[x]=b[0]^b[x]; for(register unsigned i=0;i<e[x].size();i++) { const int &y=e[x][i]; if(!--ind2[y]) q.push(y); } q.pop(); } } std::tr1::unordered_map<int64,std::bitset<N> > map; int main() { n=getint(),m=getint(),s=getint(),t=getint(); for(register int i=0;i<m;i++) { const int u=getint(),v=getint(),w=getint(); edge[i]=(Edge2){u,v,w}; add_edge(u,v,w); } dijkstra(s,diss); if(diss[t]==LLONG_MAX) { printf("%lld\n",(int64)n*(n-1)/2); return 0; } dijkstra(t,dist); for(register int i=1;i<=n;i++) e3[i].clear(); for(register int i=0;i<m;i++) { int u=edge[i].u,v=edge[i].v,w=edge[i].w; if(diss[u]>diss[v]) std::swap(u,v); if(diss[u]+w+dist[v]==diss[t]) { add_edge(u,v); vis[u]=vis[v]=true; } } int cnt=0; for(register int i=1;i<=n;i++) cnt+=!vis[i]; kahn2(); kahn(); kahn3(); for(register int i=1;i<=n;i++) { if(vis[i]) map[f[i]*g[i]][i]=true; } for(register int i=1;i<=n;i++) { if(!vis[i]) continue; if(map.count(f[t]-f[i]*g[i])) ans+=(map[f[t]-f[i]*g[i]]&b[i]).count(); if(f[i]*g[i]==f[t]) ans+=cnt; } printf("%lld\n",ans); return 0; }
[BZOJ5109]大吉大利,晚上吃雞!