[luogu3329]最小割
记原图$G=(V,E),C(s,t)$为$s,t$间最小割的容量
建立新图$T$,其构造过程$f(S)$如下(其中$S\subseteq V$)
1. 若$|S|=1$,则过程结束
2. 任取$s,t\in S$,在$T$中加入一条边$(s,t,C(s,t))$
3. 设$C(s,t)$对应的割将$V$划分为$V_{s}$和$V_{t}$,则调用$f(V_{s/t}\cap S)$
记$T_{S}$为调用$f(S)$后所得的$T$(仅保留$S$中的点)
结论:$T_{S}$为一棵树且其中$s$到$t$路径上的最小边权为$C(s,t)$
归纳,当$|S|=1$时显然成立,下面考虑$|S|>1$时
记$S_{s/t}=V_{s/t}\cap S$,省略一些显然的分析,问题即求证——
对于$x\in S_{s}$和$y\in S_{t}$,有$C(x,y)=\min \{C(x,s),C(s,t),C(y,t)\}$
注意到$C(x,y)$对应的割总将后者中的一对点割开,即左式$\ge$右式
另一方面,显然$C(x,y)\le C(s,t)$,并对$C(x,s)$对应的割分类讨论:
- 若其将$s,t$割开,则$C(x,y)\le C(s,t)\le C(x,s)$
- 若其将$x,y$割开,则$C(x,y)\le C(x,s)$
- 若其未将$s,t$或$x,y$割开,则此时的两部分与$V_{s/t}$两两求交,即将$V$分为四块
注意到每块中恰包含$s,t,x,y$中的一点,不妨用所包含的点代表对应的点集
用$A|B$表示将$A$和$B$划分开的代价,用形如$st$表示$s$和$t$间的边权和,则
$$\{s,x\}|\{t,y\}\le\{s,x,y\}|\{t\}\Longrightarrow sy+xy\le yt\\xy\le sy+xy\le yt\le ys+yt\Longrightarrow C(x,y)\le \{x\}|\{s,t,y\}\le C(x,s)=\{x,y\}|\{s,t\}$$
(通俗的来说)即形如下图的形式是不合理的
同时,根据对称性也有$C(x,y)\le C(y,t)$,即左式$\le $右式
综上,即得证
做$o(n)$次最小割,即可求得$T_{V}$,并用离线+并查集的方式维护即可
时间复杂度为$o(n\max Flow(n,m)+q)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef vector<int> vi; 5 namespace Dinic{ 6 const int N=155,M=3005; 7 int S,T,E,head[N],Head[N],d[N],vis[N]; 8 ll ans;queue<int>q; 9 struct edge{ 10 int nex,to;ll len; 11 }e[M<<1]; 12 void init(){ 13 E=0; 14 memset(head,-1,sizeof(head)); 15 memset(vis,0,sizeof(vis)); 16 } 17 void add(int x,int y,ll z){ 18 e[E]=edge{head[x],y,z},head[x]=E++; 19 e[E]=edge{head[y],x,0},head[y]=E++; 20 } 21 bool bfs(){ 22 memset(d,-1,sizeof(d)); 23 d[S]=0,q.push(S); 24 while (!q.empty()){ 25 int k=q.front();q.pop(); 26 for(int i=head[k];i!=-1;i=e[i].nex){ 27 int u=e[i].to; 28 if ((e[i].len)&&(d[u]<0))d[u]=d[k]+1,q.push(u); 29 } 30 } 31 return d[T]>=0; 32 } 33 ll dfs(int k,ll s){ 34 if (k==T)return s; 35 ll ans=0; 36 for(int &i=head[k];i!=-1;i=e[i].nex){ 37 int u=e[i].to; 38 if ((e[i].len)&&(d[u]==d[k]+1)){ 39 ll p=dfs(u,min(s,(ll)e[i].len)); 40 e[i].len-=p,e[i^1].len+=p,s-=p,ans+=p; 41 if (!s)return ans; 42 } 43 } 44 return ans; 45 } 46 ll query(int s,int t){ 47 S=s,T=t,ans=0; 48 memcpy(Head,head,sizeof(head)); 49 while (bfs()){ 50 ans+=dfs(S,1e18); 51 memcpy(head,Head,sizeof(head)); 52 } 53 return ans; 54 } 55 void dfs(int k){ 56 if (vis[k])return; 57 vis[k]=1; 58 for(int i=head[k];i!=-1;i=e[i].nex) 59 if (e[i].len)dfs(e[i].to); 60 } 61 }; 62 const int N=155; 63 int t,n,m,q,x,y,z,s,ans,fa[N],sz[N]; 64 struct edge{ 65 int x,y;ll z; 66 }e[N]; 67 int find(int k){ 68 return (k==fa[k] ? k : fa[k]=find(fa[k])); 69 } 70 void merge(int x,int y){ 71 x=find(x),y=find(y); 72 ans-=sz[x]*sz[y]; 73 fa[x]=y,sz[y]+=sz[x]; 74 } 75 namespace Gomory_Hu{ 76 Dinic::edge E[Dinic::M<<1]; 77 void add(int x,int y,ll z){ 78 e[++s]=edge{x,y,z}; 79 } 80 void solve(vi v){ 81 if (v.size()==1)return; 82 memcpy(Dinic::e,E,sizeof(E)); 83 add(v[0],v[1],Dinic::query(v[0],v[1])); 84 memset(Dinic::vis,0,sizeof(Dinic::vis)); 85 Dinic::dfs(v[0]); 86 vi vl,vr; 87 for(int i:v){ 88 if (Dinic::vis[i])vl.push_back(i); 89 else vr.push_back(i); 90 } 91 solve(vl),solve(vr); 92 } 93 void build(vi v){ 94 memcpy(E,Dinic::e,sizeof(E)); 95 solve(v); 96 } 97 }; 98 int main(){ 99 scanf("%d",&t); 100 while (t--){ 101 scanf("%d%d",&n,&m); 102 Dinic::init(); 103 for(int i=1;i<=m;i++){ 104 scanf("%d%d%d",&x,&y,&z); 105 Dinic::add(x,y,z); 106 Dinic::e[Dinic::E-1].len=z; 107 } 108 vi v(n); 109 for(int i=0;i<n;i++)v[i]=i+1; 110 s=0,Gomory_Hu::build(v); 111 scanf("%d",&q); 112 for(int i=1;i<=q;i++){ 113 scanf("%d",&x); 114 ans=n*(n-1)/2; 115 for(int j=1;j<=n;j++)fa[j]=j,sz[j]=1; 116 for(int j=1;j<n;j++) 117 if (e[j].z>x)merge(e[j].x,e[j].y); 118 printf("%d\n",ans); 119 } 120 puts(""); 121 } 122 return 0; 123 }