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;
}

猜你喜欢

转载自www.cnblogs.com/Gloid/p/9923644.html
今日推荐