1. 程式人生 > >2229: [Zjoi2011]最小割(最小割樹)

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 }