[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 } 
View Code

 

posted @ 2022-10-05 13:21  PYWBKTDA  阅读(120)  评论(1编辑  收藏  举报