题目大意:给定一个图,多次询问有多少个点对之间的最小割小于等于某个值
最小割分治- -
首先朴素的想法是做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;
}