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

最新文章

  1. Python开发【第十七篇】:MySQL(一)
  2. C#之设置无边框后如何移动窗体(转)
  3. 慕课网-安卓工程师初养成-6-3 如何使用 Java 中的数组
  4. 关于Redis中的Replication
  5. angular_$attrs
  6. 自动档车的P档和N档的区别
  7. MySQL 获得当前日期时间 函数
  8. java 命名代码检查-注解处理器
  9. ios7 自定义UINavigationBar UIBarButtonItem 10px的偏移纠正
  10. Android EditText如何去除边框添加下划线
  11. PHP练习题(一)
  12. hdu 4287
  13. Apache和Nginx下禁止访问特定的目录或文件
  14. chrome插件演示,经js转让chrome api清除浏览器缓存
  15. Java高新技术 JavaBean内省
  16. asp.netMVC4使用Bootstrap4
  17. 【运维】在Windows上使用IIS方向代理配置Websocket
  18. 关于C++用法的学习心得
  19. vue回调函数无法更改model的值
  20. 11g统计信息自动收集任务

热门文章

  1. memcached的内存管理与删除机制
  2. linux查看端口状态相关命令
  3. 2016.11.14 MIT challenge之课程总览
  4. Android5 Zygote 与 SystemServer 启动流程分析
  5. C 标准库 - &lt;assert.h&gt;
  6. 每天5道面试题(二)java基础
  7. 【X240 QQ视频对方听不到声音】解决方法
  8. Vue DOM事件
  9. 搭建局域网maven仓库
  10. MongoDB入门学习(二):MongoDB的基本概念和数据类型