BZOJ4435 : [Cerc2015]Juice Junctions

Claris發表於2016-03-20

最大流=最小割,而因為本題點的度數不超過3,所以最小割不超過3,EK演算法的複雜度為$O(n+m)$。

通過分治求出最小割樹,設$f[i][j][k]$表示最小割為$i$時,$j$點在第$k$次分治過程中是否與$S$連通,$h[i][j]$為$f[i][j][k]$的hash值,那麼如果$h[k][i]=h[k][j]$,則說明$i$和$j$之間的最小割不超過$k$。

時間複雜度$O(n(n+m))$,需要大量常數優化。

 

#include<cstdio>
#include<cstring>
#define N 3010
struct E{short u,v,nxt,f;}e[9010];
int n,m,i,j,k,a[N],S,T,ed=1,g[N],h[N],q[N],maxflow,ans;unsigned int hash[4][N],pos=1;
inline void add(int u,int v,int f){e[++ed].u=u;e[ed].v=v;e[ed].f=f;e[ed].nxt=g[u];g[u]=ed;}
inline bool bfs(){
  int*l=q,*r=q+1,i;
  memset(h+1,-1,sizeof(int)*n);
  h[q[0]=S]=0;
  while(l<r)for(i=g[*l++];i;i=e[i].nxt)if(h[e[i].v]<0&&e[i].f)h[*r++=e[i].v]=i;
  return h[T]!=-1;
}
void solve(int l,int r){
  if(l>=r)return;
  int i,j;
  for(i=2;i<=ed;i++)e[i].f=e[i^1].f=1;
  S=a[r],T=a[l],maxflow=0;
  while(bfs())for(maxflow++,i=T;i!=S;i=e[j].u)e[j=h[i]].f--,e[j^1].f++;
  unsigned int*p=hash[maxflow]+1;
  for(pos*=233,i=1;i<=n;p++)if(~h[i++])*p+=pos;
  int*L=q+l,*R=q+r,*k=a+l;
  while(k<=a+r)if(h[*k]<0)*L++=*k++;else *R--=*k++;
  memcpy(a+l,q+l,sizeof(int)*(r-l+1));
  solve(l,R-q),solve(L-q,r);
}
int main(){
  scanf("%d%d",&n,&m);
  while(m--)scanf("%d%d",&i,&j),add(i,j,1),add(j,i,1);
  for(i=1;i<=n;i++)a[i]=i;
  solve(1,n);
  for(i=1;i<=n;i++)for(j=i+1;j<=n;j++)for(k=0;k<4;k++)if(hash[k][i]!=hash[k][j]){ans+=k;break;}
  return printf("%d",ans),0;
}