zoukankan      html  css  js  c++  java
  • 演艺

    演艺

    题目描述

    一张 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;
    }
     
  • 相关阅读:
    oracle 触发器的编写
    单例类与常见双下方法
    实现高效率的冒泡排序
    面向对象基础(五)
    面向对象基础(四)
    面向对象基础(三)
    面向对象基础(二)
    面向对象(基础)
    四指针法
    因数法
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358748.html
Copyright © 2011-2022 走看看