[BZOJ5109]大吉大利,晚上吃鸡!

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

输出一行表示答案

Sample Input

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

Sample Output

6
【样例 1 解释】
合法的方案为 < 2, 3 >, < 2, 4 >, < 4, 3 >, < 4, 5 >, < 6, 3 >, < 6, 5 > 。
 
浓浓的码农气息~
首先我们随便找出了一个最短路在上面选$A$点,且$B$点不能在上边
很显然如果$A$不在上面的话就会存在从$S$到$T$的不经过$A$和$B$的最短路
然后我们建立最短路图,可以发现若$B$点不在最短路图上,那么$B$点可以和最短路图上的所有割点加上$S$和$T$组成一组合法方案
若在最短路图上且不在选定的最短路上,那么可以发现能与$B$组成合法方案的$A$点是一段区间
这是因为如果$A$能走到$B$,那么$A$之前的点也可以走到$B$,如果$B$能走到$A$,那么$B$也可以走到$A$后面的点
然后我们可以用拓扑排序求出这个区间,最后把合法的答案累加起来即可
代码:
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 #define M 100010
  7 #define ll long long
  8 #define int long long
  9 using namespace std;
 10 int n,m,num,cnt,tim,S,T,root,tot;
 11 int head[M],dis[M],pre[M],l[M],r[M],a[M],b[M],c[M];
 12 int low[M],dfn[M],dig[M],f[M];
 13 ll ans;bool vis[M],flag[M],cut[M];
 14 struct point{int to,next,dis;}e[M<<1];
 15 void add(int from,int to,int dis)
 16 {
 17     e[++num].next=head[from];
 18     e[num].to=to;
 19     e[num].dis=dis;
 20     head[from]=num;
 21 }
 22 void SPFA(int s)
 23 {
 24     memset(dis,1,sizeof(dis));dis[s]=0;
 25     queue<int>q;q.push(s);
 26     while(!q.empty())
 27     {
 28         int x=q.front();q.pop();
 29         vis[x]=false;
 30         for(int i=head[x];i;i=e[i].next)
 31         {
 32             int to=e[i].to;
 33             if(dis[to]>dis[x]+e[i].dis)
 34             {
 35                 pre[to]=x;
 36                 dis[to]=dis[x]+e[i].dis;
 37                 if(!vis[to])
 38                 {
 39                     vis[to]=true;
 40                     q.push(to);
 41                 } 
 42             }
 43         }
 44     }
 45 }
 46 void Getgraph(int s)
 47 {
 48     memset(vis,0,sizeof(vis));
 49     queue<int>q;q.push(s);
 50     while(!q.empty())
 51     {
 52         int x=q.front();q.pop();flag[x]=true;
 53         for(int i=head[x];i;i=e[i].next)
 54         {
 55             int to=e[i].to;
 56             if(dis[x]==dis[to]+e[i].dis)
 57             {
 58                 if(!vis[to]) vis[to]=true,q.push(to);
 59                 a[++cnt]=to,b[cnt]=x,c[cnt]=e[i].dis;
 60             }
 61         }
 62     }
 63 }
 64 void topsort(int s,int opt)
 65 {
 66     queue<int>q;q.push(s);
 67     while(!q.empty())
 68     {
 69         int x=q.front();q.pop();flag[M]=true;
 70         for(int i=head[x];i;i=e[i].next)
 71         {
 72             int to=e[i].to;
 73             if(!opt) l[to]=max(l[to],l[x]);
 74             else r[to]=min(r[to],r[x]);
 75             if(--dig[to]==0) q.push(to);
 76         }
 77     }
 78 }
 79 void tarjan(int x)
 80 {
 81     int flag=0;
 82     dfn[x]=low[x]=++tim;
 83     for(int i=head[x];i;i=e[i].next)
 84     {
 85         int to=e[i].to;
 86         if(!dfn[to])
 87         {
 88             tarjan(to);
 89             low[x]=min(low[x],low[to]);
 90             if(dfn[x]<=low[to])
 91             {
 92                 flag++;
 93                 if(x!=root||flag>1)
 94                 {
 95                     if(!cut[x]) tot++;
 96                     cut[x]=true;
 97                 }
 98             }
 99         }
100         else low[x]=min(low[x],dfn[to]);
101     }
102 }
103 main()
104 {
105     scanf("%lld%lld%lld%lld",&n,&m,&S,&T);
106     for(int i=1;i<=m;i++)
107     {
108         int a,b,c;scanf("%lld%lld%lld",&a,&b,&c);
109         add(a,b,c),add(b,a,c);
110     }
111     SPFA(S);
112     if(dis[T]>1e13) {printf("%lld\n",1ll*n*(n-1)/2);return 0;}
113     Getgraph(T);
114     memset(head,0,sizeof(head)),num=0;
115     for(int i=1;i<=cnt;i++)
116     {
117         add(a[i],b[i],c[i]);
118         add(b[i],a[i],c[i]);
119     }
120     root=S,tarjan(S);
121     int len=0;
122     for(int i=T;i;i=pre[i]) f[i]=++len;
123     for(int i=T;i;i=pre[i]) f[i]=len-f[i]+1;
124     for(int i=1;i<=n;i++) l[i]=1,r[i]=len;
125     for(int i=T;i;i=pre[i]) l[i]=r[i]=f[i];
126     memset(head,0,sizeof(head)),num=0;
127     for(int i=1;i<=cnt;i++) add(a[i],b[i],c[i]);
128     topsort(S,0); 
129     memset(head,0,sizeof(head)),num=0;
130     for(int i=1;i<=cnt;i++) add(b[i],a[i],c[i]);
131     topsort(T,1);
132     int k=0;
133     if(!cut[S]) tot++;
134     if(!cut[T]) tot++;
135     for(int i=1;i<=n;i++) 
136     {
137         if(!flag[i]) ans+=tot;
138         else ans+=max(0ll,r[i]-l[i]-1);
139     }
140     printf("%lld\n",ans);
141     return 0;
142 }

猜你喜欢

转载自www.cnblogs.com/Slrslr/p/10014124.html