题目描述
小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: ”对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。
对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割“
现给定一张无向图,小白有若干个形如”图中有多少对点它们的最小割的容量不超过x呢“的疑问,小蓝虽然很想回答这些问题,但小蓝最近忙着挖木块,于是作为仍然是小蓝的好友,你又有任务了。
输入输出格式
输入格式:
输入文件第一行有且只有一个正整数T,表示测试数据的组数。 对于每组测试数据, 第一行包含两个整数n,m,表示图的点数和边数。 下面m行,每行3个正整数u,v,c(1<=u,v<=n,0<=c<=106),表示有一条权为c的无向边(u,v) 接下来一行,包含一个整数q,表示询问的个数 下面q行,每行一个整数x,其含义同题目描述。
输出格式:
对于每组测试数据,输出应包括q行,第i行表示第i个问题的答案。对于点对(p,q)和(q,p),只统计一次(见样例)。两组测试数据之间用空行隔开。
输入输出样例
输入样例#1:
1
5 0
1
0
输出样例#1:
10
【数据范围】
对于100%的数据 T
注意是双向边
cogs上好像对输出格式没有检验,怪不得我在cogs上A了之后bzoj和luogu死活WA
#include<cstdio>
#include<cstring>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn = 970;
const int maxm = 100006;
int cnt,h[maxn],nx[maxm<<1],to[maxm<<1],cap[maxm<<1];
int cur[maxn];
int lev[maxn],q[maxn],l,r;
int T,N,M,Q;
int id[maxn],tmp[maxn];
bool vis[maxn];
int ans[2000][2000];
void ins(int u,int v,int c){
to[cnt]=v;nx[cnt]=h[u];h[u]=cnt;cap[cnt]=c;cnt++;
}
bool bfs(int _s,int _t){
l=r=0;memset(lev,-1,sizeof(lev));
q[r++]=_s;lev[_s]=0;
while(l<r){
int t=q[l++];
for(int i=h[t];i!=-1;i=nx[i]){
if(lev[to[i]] == -1 && cap[i]>0){
lev[to[i]] = lev[t]+1;
q[r++]=to[i];
}
}
}
return lev[_t]!=-1;
}
int dfs(int _t,int _nd,int _fl){
if(_t == _nd)return _fl;
int w=0,used=0;
for(int i=cur[_nd];i!=-1;i=nx[i]){
if(lev[to[i]] == lev[_nd]+1){
w=_fl-used;
w=dfs(_t,to[i],min(cap[i],w));
used+=w;
cap[i]-=w;cap[i^1]+=w;
if(cap[i]>0)cur[_nd]=i;
if(used==_fl)return _fl;
}
}
if(!used)cur[_nd]=-1;
return used;
}
int dinic(int _s,int _t){
int rt=0;
while(bfs(_s,_t)){
for(int i=1;i<=N;i++)cur[i]=h[i];
rt+=dfs(_t,_s,0x3f3f3f3f);
}
return rt;
}
int read(){
int rt=0,fl=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')fl=-1;ch=getchar();}
while(ch>='0' && ch<='9'){rt=rt*10+ch-'0';ch=getchar();}
return rt*fl;
}
void dfs2(int _nd){
vis[_nd]=1;
for(int i=h[_nd];i!=-1;i=nx[i])
if(cap[i]>0 && vis[to[i]]==0){
dfs2(to[i]);
}
}
void rebuild(){
for(int i=0;i<=cnt;i+=2)cap[i]=cap[i^1]=(cap[i]+cap[i^1])>>1;
}
void solve(int L,int R)
{
//cout<<L<<" "<<R<<endl;
//printf("%d %d\n",l,r);
if(L==R)return;
rebuild();
int fl=dinic(id[L],id[R]);
memset(vis,0,sizeof(vis));
dfs2(id[L]);
for(int i=1;i<=N;i++){
if(vis[i]==0)continue;
for(int j=1;j<=N;j++){
if(!vis[j]){
ans[i][j]=ans[j][i]=min(fl,ans[i][j]);
}
}
}
int _l=L,_r=R;
for(int i=L;i<=R;i++)vis[id[i]] ? tmp[_l++]=id[i] : tmp[_r--]=id[i];
for(int i=L;i<=R;i++)id[i]=tmp[i];
solve(L,_l-1);solve(_r+1,R);
}
int main()
{
// freopen("mincuto.in","r",stdin);
// freopen("mincuto.out","w",stdout)
;T=read();
while(T--){
memset(h,-1,sizeof(h));
N=read();M=read();
for(int i=1;i<=N;i++)id[i]=i;
for(int i=1;i<=M;i++){
int a,b,c;
a=read();b=read();c=read();
ins(a,b,c);ins(b,a,c);
}
// printf("%d",dinic(1,N));
memset(ans,0x3f,sizeof(ans));
Q=read();
solve(1,N);
for(int i=1;i<=Q;i++){
int buf = read();
int rt=0;
for(int j=1;j<=N;j++)
for(int k=j+1;k<=N;k++)
if(ans[j][k]<=buf){
rt++;
}
printf("%d\n",rt);
}
puts("");
}
return 0;
}