【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
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; }
| 欢迎来原网站坐坐! >原文链接<