• bzoj5109(图论好题)


    我的参考题解:https://www.cnblogs.com/ccz181078/p/7907022.html;

    不过我感觉题解的压位有问题,(1<<x)还不炸上天。不过这题数据水,好像怎么写都能对,这里放上我认为正确的写法

    //正经解法是计算一个F(x)表示经过x的最短路条数,然后找F(A)+F(B)=F(T),用map来做。
    //而且F(x)可能很大,还要取模,一个不够的话可能还要取两个。
    //而网上的这种随机算法相比之下就显得很简洁了(但由于这题数据很弱好像这部分写错也可以过)
    //关于这种做法的正确性,显然所有的最短路都经过的点的f值为0
    //那么为什么靠两个f值相同且非0且不能在树形图中互达的点能将图分成两个部分呢,我们可以考虑用一个点将两部分连起来
    //这样这个点的f值为0,也就是说它能到所有点,那把它去掉图当然被分成两个部分。
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long i64;
    typedef unsigned long long u64;
    typedef unsigned int u32;
    const int N=5e4+5;
    int n,m,pp,cp,fa[N],S,T,last[N],pre[N*2],other[N*2],w[N*2],t;
    void add(int x,int y,int z){
        ++t;pre[t]=last[x];last[x]=t;other[t]=y;w[t]=z;
    }
    struct node{
        int id;
        i64 dis;
        bool operator<(const node&a)const{
            return dis>a.dis;
        }
    }A,B;
    priority_queue<node>q;
    bool vis[N];
    i64 dis[N],ans=0;
    u64 f[N];
    u32 can[N][N/32+5];
    int _get(u32*a,int x){return (a[x>>5]>>(x&31))&1;}
    void _set(u32*a,int x){a[x>>5]|=1<<(x&31);}
    void _or(u32*a,u32*b){
        int p=n/32+1;
        for(int i=0;i<=p;i+=4){
            a[i]|=b[i];a[i+1]|=b[i+1];
            a[i+2]|=b[i+2];a[i+3]|=b[i+3];
        }
    }
    void f1(int x){//从T往回找最短路图,我觉得和从S开始找是一样的。
        vis[x]=1;
        for(int i=last[x];i;i=pre[i]){
            int v=other[i];
            if(dis[v]+w[i]==dis[x]){
                if(!vis[v])fa[v]=x,f1(v);
                else{
                    u64 z=rand();
                    z=z<<31^rand();
                    f[x]^=z;f[fa[v]]^=z;
                }
            }
        }
    }
    struct hehe{
        int id;
        u64 v,dis;
        bool operator<(const hehe&a)const{
            return v!=a.v?v<a.v:dis>a.dis;
        }
    }tmp[N];
    void f2(int x){
        _set(can[x],x);
        vis[x]=0;
        for(int i=last[x];i;i=pre[i]){
            int v=other[i];
            if(dis[v]+w[i]==dis[x]){
                if(vis[v])f2(v),f[x]^=f[v];
                _or(can[x],can[v]);
            }
        }
        if(f[x])tmp[pp++]=(hehe){x,f[x],dis[x]};
        else ++cp;
    }
    void calc(){
        f1(T);f2(T);
        sort(tmp,tmp+pp);
        for(int i=0,j=0;i<pp;i=j){
            int t=1;
            for(++j;j<pp&&tmp[i].v==tmp[j].v;++j)t+=_get(can[tmp[i].id],tmp[j].id);
            //图一定可以分成两个部分,一部分是经过A的最短路,一部分是经过B的,两部分没有交集。
            ans+=i64(j-i-t)*t;//因为f值相同的是按dis值排序的,所以此时的f一定是按A,B分的两个集合中的一个。
        }
        ans+=cp*i64(n-cp-pp);
        printf("%lld
    ",ans);
        //system("pause");
    }
    bool dijkstra(){
        for(int i=0;i<=n;++i)dis[i]=1ll<<60;
        A.id=S;A.dis=0;dis[S]=0;q.push(A);
        while(!q.empty()){
            B=q.top();q.pop();
            if(B.dis!=dis[B.id])continue;
            if(B.id==T){calc();return 1;}
            for(int i=last[B.id];i;i=pre[i]){
                int v=other[i];
                if(dis[v]>dis[B.id]+w[i]){
                    dis[v]=dis[B.id]+w[i];
                    A.id=v;A.dis=dis[v];q.push(A);
                }
            }
        }
        return 0;
    }
    int main(){
        int x,y,z;
        cin>>n>>m>>S>>T;
        srand(n^m^T^S^12341);
        for(int i=1;i<=m;++i){
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);add(y,x,z);
        }
        if(!dijkstra())printf("%lld
    ",n*i64(n-1)/2);
        //system("pause");
        return 0;
    }
  • 相关阅读:
    整合SSH遇到的问题
    学习动态代理实现业务层的事务控制遇到的问题
    docker局域网独立IP外网访问配置
    第23次CSP-D题解法
    Nordic Bluetooth 切换到DFU Mode
    MySQL事务、锁和MVCC
    深拷贝和浅拷贝的区别是什么?
    python是如何进行内存管理的
    数据库的事务
    斐波那契数列
  • 原文地址:https://www.cnblogs.com/dibaotianxing/p/8335885.html
Copyright © 2020-2023  润新知