题目大意:给定一个图,多次询问有多少个点对之间的最小割小于等于某个值
最小割分治- -
首先朴素的想法是做O(n^2)遍网络流 但是这样显然是过不去的
根据一些结论,最小割最多有n-1个,这n-1个最小割构成一个最小割树
别问我为什么- -
因此我们分治寻找这n-1个最小割
每层分治,先任选两个点作为源汇做一遍最小割
然后找出S集和T集,对所有S集的点和T集的点构成的点对用本次得到的最小割更新一遍
注意更新的是全部S集和全部T集,不只是本次分治内部的S集和T集
然后将本次分治的点分成S集和T集,对两个集合分治处理即可
然后就搞定了- - 最小割树啥的我回头再研究下吧- -
此外留个念
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 160 #define INF 0x3f3f3f3f using namespace std; struct abcd{ int to,f,next; }table[6060]; int head[M],tot=1; int n,m,q,S,T; int map[M][M]; int a[M],_a[M]; void Initialize() { memset(head,0,sizeof head); tot=1; memset(map,0x3f,sizeof map); } void Add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } namespace Max_Flow{ int dpt[M]; bool BFS() { static int q[M]; int i,r=0,h=0; memset(dpt,-1,sizeof dpt); dpt[S]=1;q[++r]=S; while(r!=h) { int x=q[++h]; for(i=head[x];i;i=table[i].next) if(table[i].f&&!~dpt[table[i].to]) { dpt[table[i].to]=dpt[x]+1; q[++r]=table[i].to; if(table[i].to==T) return true; } } return false; } int Dinic(int x,int flow) { int i,left=flow; if(x==T) return flow; for(i=head[x];i&&left;i=table[i].next) if(table[i].f&&dpt[table[i].to]==dpt[x]+1) { int temp=Dinic(table[i].to,min(left,table[i].f) ); left-=temp; table[i].f-=temp; table[i^1].f+=temp; } if(left) dpt[x]=-1; return flow-left; } } void Restore() { int i; for(i=2;i<=tot;i+=2) table[i].f=table[i^1].f=table[i].f+table[i^1].f>>1; } void DFS(int x,bool v[]) { int i; v[x]=1; for(i=head[x];i;i=table[i].next) if( table[i].f && !v[table[i].to] ) DFS(table[i].to,v); } void Divide_And_Conquer(int l,int r) { using namespace Max_Flow; static bool v[M]; if(l==r) return ; int i,j,temp=0; Restore();S=a[l];T=a[r]; while( BFS() ) temp+=Dinic(S,INF); memset(v,0,sizeof v); DFS(S,v); for(i=1;i<=n;i++) if(v[i]) for(j=1;j<=n;j++) if(!v[j]) map[i][j]=map[j][i]=min(map[i][j],temp); int _l=l,_r=r; for(i=l;i<=r;i++) if(v[a[i]]) _a[_l++]=a[i]; else _a[_r--]=a[i]; memcpy(a+l,_a+l,sizeof(a[0])*(r-l+1) ); Divide_And_Conquer(l,_l-1); Divide_And_Conquer(_r+1,r); } int main() { int T,i,j,x,y,z; for(cin>>T;T;T--) { Initialize(); cin>>n>>m; for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); Add(x,y,z);Add(y,x,z); } for(i=1;i<=n;i++) a[i]=i; Divide_And_Conquer(1,n); for(cin>>q;q;q--) { scanf("%d",&x); int ans=0; for(i=1;i<=n;i++) for(j=1;j<i;j++) if(map[i][j]<=x) ++ans; printf("%d\n",ans); } puts(""); } return 0; }