大吉大利,晚上吃鸡!

刚才打了一会\(surviv\),真的爽连吃三把。。。

不皮了不皮了,我怎么可能打\(surviv\)这种东西呢?

关于这道题,我风骨傲天愿称之为天天爱跑步·改!

首先明确题意,对于任意的最短路径都必须经过\(A\)\(B\)且不能同时经过。

不妨设\(f[i]\)表示经过\(i\)的最短路。

则一定有\(f[A]+f[B]=f[T]\)

先不急着处理这个式子,我们先考虑整体问题的处理方式。

因为任意一条最短路一定经过\(A\)\(B\),所以我们不妨任意抽出一条最短路来做。

我们发现,对于一个不在该路径上的点,它仅有可能和该路径上的一段点(连续)成为合法点对。

如果我们统计所有不在该路径上但又在最短路径上的点与这条路径的点的答案,一定不会有遗漏。

那我们就可以开个桶,内存\(f[]\)的值,枚举最短路径上的点。

先将左端点为\(i\)的加进桶中(此时他们可以开始产生影响)

对于每个点,找到桶中\(f[T]-f[i]\)的个数加进答案。

然后再将右端点为\(i\)的删去(此时他们不会再产生贡献了)

至于求\(f\)和那一段点,分别两边\(Dijstra\)和两边拓扑就好了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=5e5+10;
map<int,int> MP;
vector<int> LL[N],RR[N];
int num_edge,n,m,S,T,Sum,ans;
int Dis[N][2],Vis[N],Dag[N],R[N],f[N];
int head[N<<1],Cnt[N][2],Nex[N],L[N],Rod[N];
struct Edge{int next,to,dis;} edge[N<<1];
inline void Add(int from,int to,int dis)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].dis=dis;
    edge[num_edge].to=to;
    head[from]=num_edge;
}
inline void Dijstra_For_Count(int X,int Typ)
{
    priority_queue<pair<int,int> > Q;
    Q.push(make_pair(0,X));
    memset(Vis,0,sizeof(Vis));
    memset(Nex,0,sizeof(Nex));
    Cnt[X][Typ]=1,Dis[X][Typ]=0;
    while(Q.size())
    {
        int x=Q.top().second;Q.pop();
        if(Vis[x]) continue;Vis[x]=1;
        for(int i=head[x];i;i=edge[i].next)
            if(Dis[edge[i].to][Typ]>Dis[x][Typ]+edge[i].dis)
            {
                Dis[edge[i].to][Typ]=Dis[x][Typ]+edge[i].dis;
                Cnt[edge[i].to][Typ]=Cnt[x][Typ],Nex[edge[i].to]=x;
                Q.push(make_pair(Dis[edge[i].to][Typ],edge[i].to));
            }
            else if(Dis[edge[i].to][Typ]==Dis[x][Typ]+edge[i].dis)
                    Cnt[edge[i].to][Typ]+=Cnt[x][Typ];
    }
}
inline void TopSort(int Typ)
{
    memset(Dag,0,sizeof(Dag));
    queue<int> Q;
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=edge[j].next)
            if(Dis[edge[j].to][Typ^1]+Dis[i][Typ]+edge[j].dis==Dis[0][T])
                Dag[edge[j].to]++;
    for(int i=1;i<=n;i++) if(!Dag[i]) Q.push(i);
    while(Q.size())
    {
        int x=Q.front();Q.pop();
        for(int i=head[x];i;i=edge[i].next)
            if(Dis[edge[i].to][Typ^1]+Dis[x][Typ]+edge[i].dis==Dis[0][T])
            {
                if(!(--Dag[edge[i].to])) Q.push(edge[i].to);
                if(!Typ) L[edge[i].to]=max(L[edge[i].to],L[x]);
                else R[edge[i].to]=min(R[edge[i].to],L[x]);
            }
    }
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
    memset(Dis,0x3f,sizeof(Dis));
    n=read(),m=read(),S=read(),T=read();
    for(int i=1,u,v,d;i<=m;i++)
        u=read(),v=read(),d=read(),Add(u,v,d),Add(v,u,d);
    Dijstra_For_Count(S,0);Dijstra_For_Count(T,1);
    if(!Cnt[T][0]) {printf("%lld\n",n*(n-1)/2);return 0;}
    for(int i=S;i;i=Nex[i]) Rod[++Sum]=i,L[i]=Sum+1,R[i]=Sum-1;
    for(int i=1;i<=n;i++) if(!L[i]&&!R[i]) L[i]=1,R[i]=Sum;
    TopSort(0);TopSort(1);
    for(int i=1;i<=n;i++)
    {
        if(Dis[i][0]+Dis[i][1]==Dis[T][0]) f[i]=Cnt[i][0]*Cnt[i][1];
        if(L[i]>R[i]) continue;LL[L[i]].push_back(i);RR[R[i]].push_back(i);
    }
    for(int i=1;i<=Sum;i++)
    {
        for(int j=0;j<(int)LL[i].size();j++) ++MP[f[LL[i][j]]];
        ans+=MP[f[T]-f[Rod[i]]];
        for(int j=0;j<(int)RR[i].size();j++) --MP[f[RR[i][j]]];
    }
    printf("%lld",ans);
}   

猜你喜欢

转载自www.cnblogs.com/wo-shi-zhen-de-cai/p/11823136.html