bzoj2229: [Zjoi2011]最小割(分治最小割+最小割树思想)
2229: [Zjoi2011]最小割
题目:传送门
题解:
一道非常好的题目啊!!!
蒟蒻的想法:暴力枚举点对跑最小割记录...绝对爆炸啊....
开始怀疑是不是题目骗人...难道根本不用网络流???一看路牌....分治最小割?最小割树?
然后开始各种%论文...
简单来说吧,根据各种本蒟蒻不会证明的理论,那么:所有最小割都不是完全独立的,总共有n-1种(也就是树上的n-1条边)最小割 恰好和树的定义一样啊!
那么用一个solve递归函数来解决,一开始任意找两个点作为st和ed来最小割,然后分治,在分开的两个集合中继续递归,用数组记录答案
以上都是根据边所进行的离线操作,然后输入Q个询问,直接在线输出答案就ok
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int inf=999999999; 8 struct node 9 { 10 int x,y,c,next,other; 11 }a[210000];int len,last[110000]; 12 int st,ed,n,m,T,ans; 13 void ins(int x,int y,int c) 14 { 15 int k1,k2; 16 k1=++len; 17 a[len].x=x;a[len].y=y;a[len].c=c; 18 a[len].next=last[x];last[x]=len; 19 20 k2=++len; 21 a[len].x=y;a[len].y=x;a[len].c=c; 22 a[len].next=last[y];last[y]=len; 23 24 a[k1].other=k2; 25 a[k2].other=k1; 26 } 27 int list[110000],h[110000],head,tail; 28 bool bt_h() 29 { 30 memset(h,0,sizeof(h));h[st]=1; 31 list[1]=st;head=1;tail=2; 32 while(head!=tail) 33 { 34 int x=list[head]; 35 for(int k=last[x];k;k=a[k].next) 36 { 37 int y=a[k].y; 38 if(h[y]==0 && a[k].c) 39 { 40 h[y]=h[x]+1; 41 list[tail++]=y; 42 } 43 } 44 head++; 45 } 46 if(h[ed])return true; 47 return false; 48 } 49 int find_flow(int x,int flow) 50 { 51 if(x==ed)return flow; 52 int s=0,t; 53 for(int k=last[x];k;k=a[k].next) 54 { 55 int y=a[k].y; 56 if(h[y]==h[x]+1 && a[k].c && s<flow) 57 { 58 s+=t=find_flow(y,min(a[k].c,flow-s)); 59 a[k].c-=t;a[a[k].other].c+=t; 60 } 61 } 62 if(s==0)h[x]=0; 63 return s; 64 } 65 int d[110000],num[110000],sta[110000],anss[1100][1100]; 66 void re_num(int x) 67 { 68 num[x]=1; 69 for(int k=last[x];k;k=a[k].next) 70 { 71 int y=a[k].y; 72 if(a[k].c && !num[y]) 73 re_num(y); 74 } 75 } 76 void solve(int l,int r) 77 { 78 if(l==r)return ; 79 for(int i=1;i<=len;i+=2)a[i].c=a[i+1].c=(a[i].c+a[i+1].c)>>1;//将边权重置 80 st=d[l];ed=d[r];ans=0; 81 while(bt_h())ans+=find_flow(st,inf); 82 memset(num,0,sizeof(num)); 83 re_num(st); 84 for(int i=1;i<=n;i++) 85 if(num[i]) 86 for(int j=1;j<=n;j++) 87 if(!num[j]) 88 anss[i][j]=anss[j][i]=min(anss[i][j],ans); 89 int L=l,R=r; 90 for(int i=l;i<=r;i++) 91 { 92 if(num[d[i]])sta[L++]=d[i]; 93 else sta[R--]=d[i]; 94 } 95 for(int i=l;i<=r;i++)d[i]=sta[i]; 96 solve(l,L-1);solve(R+1,r);//分治,递归 97 } 98 int main() 99 { 100 scanf("%d",&T); 101 while(T--) 102 { 103 scanf("%d%d",&n,&m); 104 len=0;memset(last,0,sizeof(last));int x,y,c; 105 for(int i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&c),ins(x,y,c); 106 for(int i=1;i<=n;i++)d[i]=i;memset(anss,63,sizeof(anss)); 107 solve(1,n); 108 int Q;scanf("%d",&Q); 109 while(Q--) 110 { 111 scanf("%d",&x);int cnt=0; 112 for(int i=1;i<=n;i++) 113 for(int j=i+1;j<=n;j++) 114 if(anss[i][j]<=x) 115 cnt++; 116 printf("%d\n",cnt); 117 } 118 printf("\n"); 119 } 120 return 0; 121 }