• 【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;
    }

     

  • 相关阅读:
    算法竞赛进阶指南--lowbit运算,找到二进制下所有是1的位
    linux
    conda配置安装pytorch
    anaconda的安装及使用
    python操作mysql
    python生成文字云
    决策树基本原理
    Ubuntu截图软件
    ubuntu安装teamviewer
    k-最近邻算法基本原理
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7095228.html
Copyright © 2020-2023  润新知