ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::
  427 随笔 :: 0 文章 :: 14 评论 :: 0 引用

Description

最近《绝地求生:大逃杀》风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏。在游戏中,皮皮
和毛毛最喜欢做的事情就是堵桥,每每有一个好时机都能收到不少的快递。当然,有些时候并不能堵桥,皮皮和毛
毛会选择在其他的必经之路上蹲点。K博士作为一个老年人,外加有心脏病,自然是不能玩这款游戏的,但是这并
不能妨碍他对这款游戏进行一些理论分析,比如最近他就对皮皮和毛毛的战士很感兴趣。【题目描述】游戏的地图
可以抽象为一张n个点m条无向边的图,节点编号为1到n,每条边具有一个正整数的长度。假定大魔王都会从S点出
发到达T点(S和T已知),并且只会走最短路,皮皮和毛毛会在A点和B点埋伏大魔王。
为了保证一定能埋伏到大魔王,同时又想留大魔王一条生路,皮皮和毛毛约定A点和B点必须满足:
1.大魔王所有可能路径中,必定会经过A点和B点中的任意一点
2.大魔王所有可能路径中,不存在一条路径同时经过A点和B点
K博士想知道,满足上面两个条件的A,B点对有多少个,交换A,B的顺序算相同的方案

Input

第一行输入四个整数n,m,S,T(1≤n≤5×10^4,1≤m≤5×10^4,1≤S,T≤n),含义见题目描述。
接下来输入m行,每行输入三个整数u,v,w(1≤u,v≤n,1≤w≤10^9)表示存在一条长度为w的边链接u和v。
1≤n≤5×10^4,1≤m≤5×10^4,1≤w≤10^9

Output

输出一行表示答案

求出S-T最短路图,以及传递闭包

任选一个以T为根的树形图,对每条非树边u->v,选一个随机数x,将v的父亲和u分别到根的路径异或上x

若S和T不联通,任选两个点

否则,可以选两个点,使得其中一个点不在最短路图上,另一个点为最短路图上点权为0的点,或者选最短路图上两个互不能到达且权值相同且非零的点

#include<bits/stdc++.h>
typedef long long i64;
typedef unsigned long long u64;
typedef unsigned int u32;
const int N=5e4+77;
char ib[N*50],*ip=ib;
int _(){int x;scanf("%d",&x);return x;}
int n,m,S,T,e0[N],ep=2;
i64 l[N],ans=0;
struct edge{
    int to,v,nx;
}e[N*2];
struct node{
    int w;
    i64 l;
    bool operator<(const node&w)const{return l>w.l;}
};
std::priority_queue<node>q;
bool ed[N];
struct pos{
    int w;
    u64 v,l;
    bool operator<(const pos&x)const{return v!=x.v?v<x.v:l>x.l;}
}ps[N];
u64 f[N];
int fa[N],pp=0,cp=0;
u32 su[N][N/32+10];
void f1(int w){
    ed[w]=1;
    for(int i=e0[w];i;i=e[i].nx){
        int u=e[i].to;
        if(l[u]+e[i].v==l[w]){
            if(!ed[u])fa[u]=w,f1(u);
            else{
                u64 z=rand();
                z=z<<31^rand();
                f[w]^=z;
                f[fa[u]]^=z;
            }
        }
    }
}
int _get(u32*a,int x){return a[x>>5]>>x&1;}
void _set(u32*a,int x){a[x>>5]|=1<<x;}
void _or(u32*a,u32*b){
    int p=n/32+2;
    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 f2(int w){
    _set(su[w],w);
    ed[w]=0;
    for(int i=e0[w];i;i=e[i].nx){
        int u=e[i].to;
        if(l[u]+e[i].v==l[w]){
            if(ed[u])f2(u),f[w]^=f[u];
            _or(su[w],su[u]);
        }
    }
    if(f[w])ps[pp++]=(pos){w,f[w],l[w]};
    else ++cp;
}
void cal(){
    f1(T);
    f2(T);
    std::sort(ps,ps+pp);
    for(int i=0,j=0;i<pp;i=j){
        int t=1;
        for(++j;j<pp&&ps[i].v==ps[j].v;++j)t+=_get(su[ps[i].w],ps[j].w);
        ans+=i64(j-i-t)*t;
    }
    ans+=cp*i64(n-cp-pp);
    printf("%lld\n",ans);
}
int main(){
    n=_();m=_();S=_();T=_();
    srand(n^m^S^T^12341);
    for(int i=0;i<m;++i){
        int a=_(),b=_(),c=_();
        e[ep]=(edge){b,c,e0[a]};e0[a]=ep++;
        e[ep]=(edge){a,c,e0[b]};e0[b]=ep++;
    }
    for(int i=1;i<=n;++i)l[i]=1ll<<60;
    q.push((node){S,l[S]=0});
    while(q.size()){
        node w=q.top();q.pop();
        if(w.l!=l[w.w])continue;
        if(w.w==T)return cal(),0;
        for(int i=e0[w.w];i;i=e[i].nx){
            int u=e[i].to;
            if(l[u]>w.l+e[i].v)q.push((node){u,l[u]=w.l+e[i].v});
        }
    }
    printf("%lld\n",n*i64(n-1)/2);
    return 0;
}

 

posted on 2017-11-28 02:12  nul  阅读(...)  评论(... 编辑 收藏