【BZOJ4435】[Cerc2015]Juice Junctions Tarjan+hash

【BZOJ4435】[Cerc2015]Juice Junctions

Description

你被雇佣升级一个旧果汁加工厂的橙汁运输系统。系统有管道和节点构成。每条管道都是双向的,且每条管道的流量都是1升每秒。管道可能连接节点,每个节点最多可以连接3条管道。节点的流量是无限的。节点用整数1到n来表示。在升级系统之前,你需要对现有系统进行分析。对于两个不同节点s和t,s-t的流量被定义为:当s为源点,t为汇点,从s能流向t的最大流量。以下面的第一组样例数据为例,1-6的流量为3,1-2的流量为2。计算每一对满足a<b的节点a-b的流量的和。

Input

第一行包括2个整数n和m(2<=n<=3000,0<=m<=4500)——节点数和管道数。
接下来m行,每行包括两个相异整数a,b(1<=a,b<=n),表示一条管道连接节点a,b。
每个节点最多连接3条管道,每对节点最多被一条管道连接。

Output

输出一个整数——每对满足a<b的节点a-b的流量之和。

Sample Input

6 8
1 3
2 3
4 1
5 6
2 6
5 1
6 4
5 3

Sample Output

36

题解:这题还真是神啊~

考虑,每一个点对对答案的贡献只能为1,2,3,我们分别讨论这三种情况。

贡献为1或2或3:用并查集看一下是否联通就行了。
贡献为2或3:跑完Tarjan后,它们一定在同一个边双里。
贡献为3:这个的做法就比较奇葩了,我们任意删除一条边,如果无论删除那条边它们都在一个边双里,那么贡献为3。这个怎么判断呢?先枚举删除那条边,将每一种情况下i所在的边双的编号hash起来,然后比较两个hash是否相等就行了。

 

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=3010;
typedef unsigned long long ull;
ull hs[maxn];
int n,m,ans,cnt,tot,top,sum;
int to[9010],next[9010],head[maxn],dep[maxn],low[maxn],ins[maxn],sta[maxn],bel[maxn],f[maxn];
void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
void tarjan(int x,int fa,int ban)
{
	dep[x]=low[x]=++tot,ins[x]=1,sta[++top]=x;
	for(int i=head[x];i!=-1;i=next[i])
	{
		if(i==fa||i==ban||i==(ban^1))	continue;
		if(!dep[to[i]])	tarjan(to[i],i^1,ban),low[x]=min(low[x],low[to[i]]);
		else	low[x]=min(low[x],dep[to[i]]);
	}
	if(dep[x]==low[x])
	{
		sum++;
		int t;
		do
		{
			t=sta[top--],ins[t]=0,bel[t]=sum;
		}while(t!=x);
	}
}
int find(int x)
{
	return (f[x]==x)?x:(f[x]=find(f[x]));
}
int main()
{
	n=rd(),m=rd();
	int i,j,a,b;
	for(i=1;i<=n;i++)	f[i]=i;
	memset(head,-1,sizeof(head));
	for(i=1;i<=m;i++)
	{
		a=rd(),b=rd(),add(a,b),add(b,a);
		if(find(a)!=find(b))	f[f[a]]=f[b];
	}
	memset(dep,0,sizeof(dep));
	memset(low,0,sizeof(low));
	tot=top=sum=0;
	for(i=1;i<=n;i++)	if(!dep[i])	tarjan(i,-1,-1);
	for(i=1;i<=n;i++)	for(j=i+1;j<=n;j++)
	{
		if(find(i)==find(j))	ans++;
		if(bel[i]==bel[j])	ans++;
	}
	for(i=0;i<cnt;i+=2)
	{
		memset(dep,0,sizeof(dep));
		memset(low,0,sizeof(low));
		tot=top=sum=0;
		for(j=1;j<=n;j++)	if(!dep[j])	tarjan(j,-1,i);
		for(j=1;j<=n;j++)	hs[j]=hs[j]*233+bel[j];
	}
	for(i=1;i<=n;i++)	for(j=i+1;j<=n;j++)	if(hs[i]==hs[j])	ans++;
	printf("%d",ans);
	return 0;
}

 

原文地址:https://www.cnblogs.com/CQzhangyu/p/7095228.html