【洛谷5934】[清华集训2012] 最小生成树(最小割)
- 给定一张\(n\)个点\(m\)条边的无向图,现在加入一条边\((u,v,L)\),问至少需要删去多少条边才能使得它既可能出现在最小生成树中,又可能出现在最大生成树中。
- \(n\le2\times10^4,m\le2\times10^5\)
最小割
考虑\(Kruskal\)求\(MST\)的思想,就是给边按权值排个序,然后贪心地能加就加。
那么\((u,v,L)\)能出现在最小生成树中,就说明所有边权小于\(L\)的边不能使得\(u,v\)连通,那么就直接把所有边权小于\(L\)的边连上求出最小割,即最大流。
同理,能出现在最大生成树中,就说明所有边权大于\(L\)的边不能使得\(u,v\)连通,同样连边跑最大流即可。
两个答案相加就是最终的答案。
代码:\(O(Dinic)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 20000
#define M 200000
using namespace std;
int n,m,s,t,L;struct edge {int x,y,v;}e[M+5];
namespace Dinic//网络流模板
{
#define E(x) ((((x)-1)^1)+1)
#define add(x,y,f) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].F=f)
int ee,lnk[N+5],cur[N+5];struct edge {int to,nxt,F;}e[4*M+5];
I void Clear() {ee=0;for(RI i=1;i<=n;++i) lnk[i]=0;}//清空
I void Add(CI x,CI y,CI f) {add(x,y,f),add(y,x,0);}
int q[N+5],D[N+5];I bool BFS()
{
RI i,k,H=1,T=1;for(i=1;i<=n;++i) D[i]=0;D[q[1]=s]=1;W(H<=T&&!D[t])
for(i=lnk[k=q[H++]];i;i=e[i].nxt) e[i].F&&!D[e[i].to]&&(D[q[++T]=e[i].to]=D[k]+1);
return memcpy(cur,lnk,sizeof(cur)),D[t];
}
I int DFS(CI x=s,RI f=1e9)
{
if(x==t||!f) return f;RI i,g,res=0;for(i=cur[x];i;i=e[i].nxt)
{
if(!e[i].F||D[e[i].to]^(D[x]+1)||!(g=DFS(e[i].to,min(f,e[i].F)))) continue;
if(e[i].F-=g,e[E(i)].F+=g,res+=g,!(f-=g)) break;
}return cur[x]=i,res;
}
I int MaxFlow() {RI g=0;W(BFS()) g+=DFS();return g;}
}
int main()
{
RI i;for(scanf("%d%d",&n,&m),i=1;i<=m;++i) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);scanf("%d%d%d",&s,&t,&L);
for(i=1;i<=m;++i) e[i].v<L&&(Dinic::Add(e[i].x,e[i].y,1),Dinic::Add(e[i].y,e[i].x,1),0);//边权小于L的边
RI tot=Dinic::MaxFlow();Dinic::Clear();//两次网络流间要清空
for(i=1;i<=m;++i) e[i].v>L&&(Dinic::Add(e[i].x,e[i].y,1),Dinic::Add(e[i].y,e[i].x,1),0);//边权大于L的边
return printf("%d\n",tot+=Dinic::MaxFlow()),0;//两次答案相加
}
待到再迷茫时回头望,所有脚印会发出光芒