演艺

演艺

题目描述

一张 N 个点M 条无向边的图,节点编号为 1 到 N,每条边具有一个正整数的长度。 

假定黄花敦会从 S点出发到达 T 点,并且只会走最短路,wxh 和 wsq 会在 A 点和 B 点 埋伏黄花敦。 

为了保证一定能埋伏到黄花敦,同时 wxh 又想制造单独和黄花敦相处的机会,A 点和 B 点必须满足:黄花敦所有可能路径中,必定会经过 AA 点和 BB 点中的任意一点且不存在一条 路径同时经过 A 点和 B 点。 

Wxh 想知道满足上面两个条件的 A,B 点对有多少个,交换 A,B 的顺序算相同的方案。

输入

第一行四个整数 N,M,S,TN,M,S,T  ,接下来 MM 行每行三个整数 a,b,wa,b,w 表示有一条连接 aa 和 bb 的长度为 ww  的边。

输出

一行一个整数表示答案

样例输入

7 7 1 7 
1 2 2 
2 4 2 
4 6 2 
6 7 2 
1 3 2 
3 5 4 
5 7 2 

样例输出

6 

提示

【样例解释】  

<2,3>,<2,4>,<4,3>,<4,5>,<6,3>,<6,5><2,3>,<2,4>,<4,3>,<4,5>,<6,3>,<6,5> 

【数据范围和约定】

1≤n≤5×104,1≤m≤5×104,1≤w≤109


solution

首先跑出最短路网。

要求的是AB在最所有短路上并且不能有一条路既过A,又过B。

用dp求出与过每一个点的最短路数。离散化,用bitset记某一种最短路对应着哪些点。

那么这时如果有两个点的最短路的条数和等于总的最短路数,并且他么的最短路没有重合,那就是合法的(A.B)

再用另一个 bitset 把与每一个点连接的点求出来。

这里的连接指同在某一条最短路。

假设我现在要算x的答案

假设x的最短路数为A ,总最短路数为num

最短路数为n-A的点集记为S

与x相连的点集为T

x的答案为S^(S&T)

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<bitset>
#include<queue>
#include<map>
#define maxn 50005
#define inf 1e18
#define ll long long
using namespace std;
int n,m,S,T,head[maxn],tot,in[2][maxn];
int flag[maxn],HEAD[maxn],tot2,top,cnt,sz;
ll d[2][maxn],a[maxn],w[maxn],f[2][maxn],dy[maxn],ans;
map<ll,int>ls;
struct node{
    ll w;int v,nex;
}e[maxn*2],e2[maxn*2];
struct Node{
    int x;ll dist;
    bool operator <(const Node &T)const{
        return T.dist<dist;
    }
};
bitset<maxn>fl[2][maxn],fs[maxn],now;
void lj(int t1,int t2,ll t3){
    e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;
}
void Dij(int st,int p){
    priority_queue<Node>q;
    for(int i=1;i<=n;i++)d[p][i]=inf,flag[i]=0;
    d[p][st]=0;q.push((Node){st,0});
    while(!q.empty()){
        Node t=q.top();q.pop();
        if(flag[t.x])continue;
        flag[t.x]=1;
        for(int i=head[t.x];i;i=e[i].nex){
            if(!flag[e[i].v]&&d[p][e[i].v]>d[p][t.x]+e[i].w){
                d[p][e[i].v]=d[p][t.x]+e[i].w;
                q.push((Node){e[i].v,d[p][e[i].v]});
            }
        }
    }
}
void add(int t1,int t2){
    e2[++tot2].v=t2;e2[tot2].nex=HEAD[t1];HEAD[t1]=tot2;
}
void Dp(int St,int p){
    queue<int>q;
    q.push(St);f[p][St]=1;
    for(int i=1;i<=n;i++)fl[p][i][i]=1,flag[i]=0;
    while(!q.empty()){
        int t=q.front();q.pop();flag[t]=1;sz+=p;
        for(int i=head[t];i;i=e[i].nex){
            if(flag[e[i].v])continue;
            f[p][e[i].v]+=f[p][t];
            fl[p][e[i].v]|=fl[p][t];
            if(!(--in[p][e[i].v]))q.push(e[i].v);
        }
    }
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&S,&T);
    for(int i=1,t1,t2,t3;i<=m;i++){
        scanf("%d%d%d",&t1,&t2,&t3);
        lj(t1,t2,t3);lj(t2,t1,t3);
    }
    Dij(S,0);Dij(T,1);
     
    for(int k=1;k<=n;k++){
        for(int i=head[k];i;i=e[i].nex){
            if(d[0][k]+e[i].w+d[1][e[i].v]==d[0][T]){
                in[0][e[i].v]++;in[1][k]++;
                add(k,e[i].v),add(e[i].v,k);
            }
        }
    }
    for(int i=1;i<=tot2;i++)e[i]=e2[i];
    for(int i=1;i<=n;i++)head[i]=HEAD[i];
    Dp(S,0);Dp(T,1);
    for(int i=1;i<=n;i++){
        a[i]=f[0][i]*f[1][i];
        fl[0][i]|=fl[1][i];
        w[i]=a[i];
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++){
        if(!ls[a[i]])ls[a[i]]=++cnt;
        dy[cnt]=a[i];
    }
    for(int i=1;i<=n;i++)fs[ls[w[i]]][i]=1;
    ll sum=w[S];
    for(int i=1;i<=n;i++){
        ll la=sum-w[i];la=ls[la];
        if(!la)continue;
        now=(fs[la]&fl[0][i])^fs[la];
        ans+=now.count();
    }
    cout<<ans/2<<endl;
    return 0;
}
 
原文地址:https://www.cnblogs.com/liankewei/p/10358748.html