2229: [Zjoi2011]最小割(最小割树)

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位有符号整数类型范围内。
图中两个点之间可能有多条边
解题思路:
最小割树,用于解决全局任意点间的最小割。
考虑对于全局任意两个点的最小割将图分成的两部分,假如说我们在这两部分之间画一条分界线。
那么在两端各取一点再跑最小割,这时再画分界线,若两者最小割容量不同,那么那么这两条分界线一定没有交集。
贪心地想,若其中一个更优那么一定会取。
若第二条比第一条更优,那么一定说明第一遍时的两个点在第二条分界线同侧。
同时也说明,第二条分界线后除第二遍的终点以外,还会有点与这个点的最小割形成的割集与第二个割集相同。
所以可以每次取两个点跑最小割,划线。
然后下次在线同侧取点跑最小割划线,在线两端的点一定以这个割集为割集,所以更新答案即可。
分治的最坏时间复杂度为$O(n^2)$的,再套个Dinic时间复杂度为$O(n^4m)$的,不过这都是最坏的。
后者达上限非常困难前者也不容易。所以还是$O(玄学)$比较合适。
代码:
  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 const int oo=0x3f3f3f3f;
  6 struct pnt{
  7     int hd;
  8     int lyr;
  9     int now;
 10     bool vis;
 11 }p[1000];
 12 struct ent{
 13     int twd;
 14     int lst;
 15     int vls;
 16     int his;
 17 }e[1000000];
 18 int cnt;
 19 int n,m;
 20 int s,t;
 21 int app[200];
 22 int tmp[200];
 23 int ans[151][151];
 24 std::queue<int>Q;
 25 void ade(int f,int t,int v)
 26 {
 27     cnt++;
 28     e[cnt].twd=t;
 29     e[cnt].vls=v;
 30     e[cnt].his=v;
 31     e[cnt].lst=p[f].hd;
 32     p[f].hd=cnt;
 33     return ;
 34 }
 35 bool Bfs(void)
 36 {
 37     while(!Q.empty())Q.pop();
 38     for(int i=1;i<=n;i++)
 39         p[i].lyr=0;
 40     p[s].lyr=1;
 41     Q.push(s);
 42     while(!Q.empty())
 43     {
 44         int x=Q.front();
 45         Q.pop();
 46         for(int i=p[x].hd;i;i=e[i].lst)
 47         {
 48             int to=e[i].twd;
 49             if(p[to].lyr==0&&e[i].vls>0)
 50             {
 51                 p[to].lyr=p[x].lyr+1;
 52                 if(to==t)
 53                     return true;
 54                 Q.push(to);
 55             }
 56         }
 57     }
 58     return false;
 59 }
 60 int Dfs(int x,int fll)
 61 {
 62     if(x==t)
 63         return fll;
 64     for(int& i=p[x].now;i;i=e[i].lst)
 65     {
 66         int to=e[i].twd;
 67         if(p[to].lyr==p[x].lyr+1&&e[i].vls>0)
 68         {
 69             int ans=Dfs(to,std::min(fll,e[i].vls));
 70             if(ans>0)
 71             {
 72                 e[i].vls-=ans;
 73                 e[((i-1)^1)+1].vls+=ans;
 74                 return ans;
 75             }
 76         }
 77     }
 78     return 0;
 79 }
 80 int Dinic()
 81 {
 82     int ans=0;
 83     while(Bfs())
 84     {
 85         for(int i=1;i<=n;i++)
 86             p[i].now=p[i].hd;
 87         int dlt;
 88         while(dlt=Dfs(s,oo))
 89             ans+=dlt;
 90     }
 91     return ans;
 92 }
 93 void dfs(int x)
 94 {
 95     if(p[x].vis)
 96         return ;
 97     p[x].vis=true;
 98     for(int i=p[x].hd;i;i=e[i].lst)
 99     {
100         int to=e[i].twd;
101         if(e[i].vls>0)
102             dfs(to);
103     }
104     return ;
105 }
106 void Build(int l,int r)
107 {
108     if(l==r)
109         return ;
110     s=app[l],t=app[r];
111     for(int i=1;i<=cnt;i+=4)
112     {
113         e[i].vls=e[i].his;
114         e[i+1].vls=e[i+1].his;
115         e[i+2].vls=e[i+2].his;
116         e[i+3].vls=e[i+3].his;
117     }
118     int tmf=Dinic();
119     for(int i=1;i<=n;i++)
120         p[i].vis=false;
121     dfs(s);
122     for(int i=1;i<=n;i++)
123         if(p[i].vis)
124             for(int j=1;j<=n;j++)
125                 if(!p[j].vis)
126                     ans[i][j]=ans[j][i]=std::min(ans[i][j],tmf);
127     int i=l-1,j=r+1;
128     for(int k=l;k<=r;k++)
129         if(p[app[k]].vis)
130             tmp[++i]=app[k];
131         else
132             tmp[--j]=app[k];
133     for(int k=l;k<=r;k++)
134         app[k]=tmp[k];
135     Build(l,i);
136     Build(j,r);
137     return ;
138 }
139 int main()
140 {
141 //    freopen("a.in","r",stdin);
142     int T;
143     scanf("%d",&T);
144     while(T--)
145     {
146         scanf("%d%d",&n,&m);
147         cnt=0;
148         for(int i=1;i<=n;i++)
149             app[i]=i,
150             p[i].hd=0;
151         memset(ans,0x3f,sizeof(ans));
152         for(int i=1;i<=m;i++)
153         {
154             int a,b,c;
155             scanf("%d%d%d",&a,&b,&c);
156             ade(a,b,c);
157             ade(b,a,c);
158         }
159         Build(1,n);
160         int q;
161         scanf("%d",&q);
162         while(q--)
163         {
164             int x;
165             scanf("%d",&x);
166             int ansl=0;
167             for(int i=1;i<n;i++)
168                 for(int j=i+1;j<=n;j++)
169                     if(ans[i][j]<=x)
170                         ansl++;
171             printf("%d\n",ansl);
172         }
173         puts("");
174     }
175     return 0;
176 }
posted @ 2019-01-08 13:53  Unstoppable728  阅读(296)  评论(0编辑  收藏  举报