bzoj 2229[Zjoi2011]最小割 - 分治 + 最小割

2229: [Zjoi2011]最小割

Time Limit: 10 Sec  Memory Limit: 259 MB

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

Sample Output

10

【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边
 
 
这里用到了一个知识点叫最小割树
一个n点的图最多有n-1个最小割
我们可以将一个图变成一个树
则这张图中任意两点的最小割就是最小割树上两点之间最短的割
操作很简单
每次任选两点跑最小割, 分为集合s, t
在两个集合中递归下去
 
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <queue>
  4 #include <cstring>
  5 #include <algorithm>
  6 #define LL long long
  7 
  8 using namespace std;
  9 
 10 queue<int> q;
 11 const LL inf = 1e18;
 12 const int MAXN = 200;
 13 const int MAXM = 3e3 + 10;
 14 int TT, Q;
 15 int n, m;
 16 int S, T;
 17 LL u, v, c;
 18 int cnt = 0;
 19 
 20 LL ans[MAXN][MAXN];
 21 bool vis[MAXN];
 22 int a[MAXN];
 23 int temp[MAXN];
 24 int h[MAXN];
 25 int head[MAXN];
 26 
 27 struct edge {
 28     int v;
 29     LL c;
 30     int next;
 31 } g[MAXM * 2];
 32 
 33 void addedge(int u, int v, int w)
 34 {
 35     g[cnt].v = v;
 36     g[cnt].c = w;
 37     g[cnt].next = head[u];
 38     head[u] = cnt++;
 39 }
 40 
 41 inline LL read()
 42 {
 43     LL x = 0, w = 1; char ch = 0;
 44     while(ch < '0' || ch > '9') {
 45         if(ch == '-') {
 46             w = -1;
 47         }
 48         ch = getchar();
 49     }
 50     while(ch >= '0' && ch <= '9') {
 51         x = x * 10 + ch - '0';
 52         ch = getchar();
 53     }
 54     return x * w;
 55 }
 56 
 57 void restore()
 58 {
 59     for(int j = 0; j <= cnt; j++) {
 60         g[j].c = g[j ^ 1].c = ((g[j].c + g[j ^ 1].c) >> 1);
 61     }
 62 }
 63 
 64 bool BFS()
 65 {
 66     memset(h, -1, sizeof h);
 67     h[S] = 0;
 68     q.push(S);
 69     while(!q.empty()) {
 70         int t = q.front();
 71         q.pop();
 72         for(int j = head[t]; j != -1; j = g[j].next) {
 73             int to = g[j].v;
 74             if(h[to] == -1 && g[j].c) {
 75                 h[to] = h[t] + 1;
 76                 q.push(to);
 77             }
 78         }
 79     }
 80     if(h[T] == -1) {
 81         return false;
 82     }
 83     return true;
 84 }
 85 
 86 LL DFS(int x, LL f)
 87 {
 88     int used = 0;
 89     if(x == T) {
 90         return f;
 91     }
 92     for(int j = head[x]; j != -1; j = g[j].next) {
 93         int to = g[j].v;
 94         if(h[to] == h[x] + 1 && g[j].c) {
 95             LL w = f - used;
 96             w = DFS(to, min(w, g[j].c));
 97             used += w;
 98             g[j].c -= w, g[j ^ 1].c += w;
 99             if(used == f) {
100                 break;
101             }
102         }
103     }
104     if(!used) {
105         h[x] = -1;
106     }
107     return used;
108 }
109 
110 void search(int x)
111 {
112     vis[x] = 1;
113     for(int j = head[x]; j != -1; j = g[j].next) {
114         int to = g[j].v;
115         if(!vis[to] && g[j].c) {
116             search(to);
117         }
118     }
119 }
120 
121 void solve(int l, int r)
122 {
123     //cout<<l<<" "<<r<<endl;
124     if(l == r) {
125         return;    
126     }
127     restore();
128     S = a[l], T = a[r];
129     LL flow = 0;
130     while(BFS()) {
131         flow += DFS(S, inf);
132     }
133     memset(vis, 0, sizeof vis);
134     search(S);
135     int L = l, R = r;
136     for(int i = l; i <= r; i++) {
137         if(vis[a[i]]) {
138             temp[L++] = a[i];
139         } else {
140             temp[R--] = a[i];
141         }
142     }
143     for(int i = 1; i <= n; i++) {
144         if(vis[i]) {
145             for(int j = 1; j <= n; j++) {
146                 if(!vis[j]) {
147                     ans[i][j] = ans[j][i] = min(ans[i][j], flow);
148                 }
149             }
150         }
151     }
152     for(int i = l; i <= r; i++) {
153         a[i] = temp[i];
154     }
155     solve(l, L - 1), solve(R + 1, r);
156 }
157 
158 void open()
159 {
160     freopen("mincut1.in", "r", stdin);
161     //freopen("mincut.out", "w", stdout);
162 }
163 
164 void close()
165 {
166     fclose(stdin);
167     fclose(stdout);
168 }
169 int main()
170 {
171     //open();
172     TT = read();
173     while(TT--) {
174         memset(ans, 0x3f, sizeof ans);
175         memset(head, -1, sizeof head);
176         cnt = 0;
177         n = read(), m = read();
178         for(int i = 1; i <= n; i++) {
179             a[i] = i;
180         }
181         for(int i = 1; i <= m; i++) {
182             u = read(), v = read(), c = read();
183             addedge(u, v, c);
184             addedge(v, u, c);
185         }
186         solve(1, n);
187         Q = read();
188         while(Q--) {
189             int sum = 0;
190             LL x = read();
191             for(int i = 1; i <= n; i++) {
192                 for(int j = i + 1; j <= n; j++) {
193                     if(ans[i][j] <= x) {
194                         sum++;
195                     }
196                 }
197             }
198             printf("%d\n", sum);
199         }
200         printf("\n");
201     }
202 //    close();
203     return 0;
204 }
205 
206 
207 /*
208 1
209 5 0
210 1
211 0
212 
213 */
View Code

 

posted @ 2018-06-07 18:25  大财主  阅读(246)  评论(0编辑  收藏  举报