不同的最小割 bzoj-4519 Cqoi-2016

题目大意题目链接

注释:略。


想法

我们发现这和最小割那题比较像。

我们依然通过那个题说的办法一样,构建最小割树即可。

接下来就是随便怎么处理都行了。

我们可以弄一个数组把枚举到的距离都记录下来即可。

Code

#include <bits/stdc++.h>
#define N 860
#define M 17010
using namespace std;
queue<int> q;
int n,head[N],to[M],val[M],next[M],tot=1,s,t,dis[N],a[N],tmp[N],ans[N][N],v[1000000],tot;
inline void add(int x,int y,int z)
{
	to[++tot]=y,val[tot]=z,next[tot]=head[x],head[x]=tot;
	to[++tot]=x,val[tot]=z,next[tot]=head[y],head[y]=tot;
}
bool bfs()
{
	int x,i;
	memset(dis,0,sizeof(dis));
	while(!q.empty()) q.pop();
	dis[s]=1,q.push(s);
	while(!q.empty())
	{
		x=q.front(),q.pop();
		for(i=head[x];i;i=next[i])
		{
			if(val[i]&&!dis[to[i]])
			{
				dis[to[i]]=dis[x]+1;
				if(to[i]==t) return 1;
				q.push(to[i]);
			}
		}
	}
	return 0;
}
int dinic(int x,int low)
{
	if(x==t) return low;
	int temp=low,i,k;
	for(i=head[x];i;i=next[i])
	{
		if(val[i]&&dis[to[i]]==dis[x]+1)
		{
			k=dinic(to[i],min(temp,val[i]));
			if(!k) dis[to[i]]=0;
			val[i]-=k,val[i^1]+=k;
			if(!(temp-=k)) break;
		}
	}
	return low-temp;
}
void solve(int l,int r)
{
	if(l >= r) return;
	int i,j,sum=0,p1,p2;
	for(i=2;i <= tot;i+=2) val[i]=val[i^1]=(val[i]+val[i^1]) >> 1;
	s=a[l],t=a[r];
	while(bfs()) sum+=dinic(s,1<<30);
	for(i=1;i <= n;i++)
		if(dis[i])
			for(j=1;j <= n;j++)
				if(!dis[j])
					ans[i][j]=ans[j][i]=min(ans[i][j],sum);
	for(p1=i=l,p2=r;i <= r;i++)
	{
		if(dis[a[i]]) tmp[p1++]=a[i];
		else tmp[p2--]=a[i];
	}
	for(i=l;i <= r;i++) a[i]=tmp[i];
	solve(l,p2),solve(p1,r);
}
int main()
{
	int m,i,j,x,y,z,ret=0;
	scanf("%d%d",&n,&m);
	while(m--) scanf("%d%d%d",&x,&y,&z),add(x,y,z);
	for(i=1;i <= n;i++) a[i]=i;
	memset(ans,0x7f,sizeof(ans)),solve(1,n);
	for(i=1;i <= n;i++)
		for(j=i+1;j <= n;j++)
			v[++tot]=ans[i][j];
	sort(v+1,v+tot+1);
	v[0]=-1<<30;
	for(i=1;i <= tot;i++)
		if(v[i] != v[i-1])
			ret++;
	printf("%d\n",ret);
	return 0;
}

小结:最小割树的应用我就碰见了这么两道题。