2229: [Zjoi2011]最小割
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 1857 Solved: 661
[ Submit][ Status][ Discuss]
Description
小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。 对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割” 现给定一张无向图,小白有若干个形如“图中有多少对点它们的最小割的容量不超过x呢”的疑问,小蓝虽然很想回答这些问题,但小蓝最近忙着挖木块,于是作为仍然是小蓝的好友,你又有任务了。
Input
输入文件第一行有且只有一个正整数T,表示测试数据的组数。 对于每组测试数据, 第一行包含两个整数n,m,表示图的点数和边数。 下面m行,每行3个正整数u,v,c(1<=u,v<=n,0<=c<=106),表示有一条权为c的无向边(u,v) 接下来一行,包含一个整数q,表示询问的个数 下面q行,每行一个整数x,其含义同题目描述。
Output
对于每组测试数据,输出应包括q行,第i行表示第i个问题的答案。对于点对(p,q)和(q,p),只统计一次(见样例)。
两组测试数据之间用空行隔开。
Sample Input
1
5 0
1
0
5 0
1
0
Sample Output
10
【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边
【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边
HINT
Source
构建一棵最小割树,任意两点的最小割的值是树上路径中边权最小的边的权值
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 155;
const int maxm = 20020;
const int T = 8;
const int INF = ~0U >> 1;
struct E{
int to,cap,flow; E(){}
E(int to,int cap,int flow): to(to),cap(cap),flow(flow){}
}edgs[maxm];
int n,m,cnt,tot,Cnt,s,t,vis[maxn],fa[maxn][T],L[maxn]
,par[maxn],cur[maxn],val[maxn][T],A[maxn*maxn];
vector <int> v[maxn],g[maxn];
queue <int> Q;
void Add(int x,int y,int cap)
{
v[x].push_back(cnt); edgs[cnt++] = E(y,cap,0);
v[y].push_back(cnt); edgs[cnt++] = E(x,0,0);
}
bool BFS()
{
for (int i = 1; i <= n; i++) L[i] = 0;
Q.push(s); L[s] = 1; vis[s] = ++Cnt;
while (!Q.empty())
{
int k = Q.front(); Q.pop();
for (int i = 0; i < v[k].size(); i++)
{
E e = edgs[v[k][i]];
if (e.cap == e.flow || L[e.to]) continue;
L[e.to] = L[k] + 1; vis[e.to] = Cnt; Q.push(e.to);
}
}
return vis[t] == Cnt;
}
int Dinic(int x,int a)
{
if (x == t) return a; int flow = 0;
for (int &i = cur[x]; i < v[x].size(); i++)
{
E &e = edgs[v[x][i]];
if (e.cap == e.flow || L[e.to] != L[x] + 1) continue;
int f = Dinic(e.to,min(a,e.cap - e.flow));
if (!f) continue; flow += f; e.flow += f;
a -= f; edgs[v[x][i]^1].flow -= f; if (!a) return flow;
}
if (!flow) L[x] = -1; return flow;
}
void Dfs(int x)
{
for (int i = 1; i < T; i++)
{
fa[x][i] = fa[fa[x][i-1]][i-1];
val[x][i] = min(val[x][i-1],val[fa[x][i-1]][i-1]);
}
for (int i = 0; i < g[x].size(); i++)
{
int to = g[x][i];
L[to] = L[x] + 1; Dfs(to);
}
}
int LCA(int p,int q)
{
int ret = INF; if (L[p] < L[q]) swap(p,q);
for (int i = T - 1; i >= 0; i--)
if (L[p] - (1 << i) >= L[q])
ret = min(ret,val[p][i]),p = fa[p][i];
if (p == q) return ret;
for (int i = T - 1; i >= 0; i--)
if (fa[p][i] != fa[q][i])
{
ret = min(ret,val[p][i]); p = fa[p][i];
ret = min(ret,val[q][i]); q = fa[q][i];
}
ret = min(ret,val[p][0]);
ret = min(ret,val[q][0]);
return ret;
}
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
void Clear()
{
cnt = Cnt = tot = 0;
for (int i = 1; i <= n; i++) v[i].clear(),g[i].clear();
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
int Query = getint();
while (Query--)
{
n = getint(); m = getint();
while (m--)
{
int x = getint(),y,w;
y = getint(); w = getint();
Add(x,y,w); Add(y,x,w);
}
for (int i = 2; i <= n; i++) par[i] = 1;
for (int i = 2; i <= n; i++)
{
int MaxFlow = 0; s = i; t = par[i];
while (BFS())
{
for (int i = 1; i <= n; i++) cur[i] = 0;
MaxFlow += Dinic(s,INF);
}
for (int j = i + 1; j <= n; j++) if (par[j] == par[i] && vis[j] == Cnt) par[j] = i;
fa[i][0] = par[i]; val[i][0] = MaxFlow; g[par[i]].push_back(i);
for (int j = 0; j < cnt; j++) edgs[j].flow = 0;
}
L[1] = 1; Dfs(1);
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
A[++tot] = LCA(i,j);
int q = getint();
while (q--)
{
int x = getint(),Ans = 0;
for (int i = 1; i <= tot; i++)
if (A[i] <= x) ++Ans;
printf("%d\n",Ans);
}
puts(""); Clear();
}
return 0;
}