传送门

题目描述
你是活跃在历史幕后的一名特工,为了世界和平而夜以继日地努力着。
这个世界有N个国家,编号为1..N;
你的目的是在这N个国家之间建立尽可能多的友好关系。
你为了制定一个特工工作的计划,作出了一张当今国际关系的示意图。
你准备了一张非常大的画纸,先画下了代表每个国家的N个点。
接下来,为了表示现在的国际关系,画下了M个连接两个国家的有向边;
其中从国家u连向国家v的有向边,表示国家u向国家v派遣了大使,下文称作边(u,v)。
这样就做出了N个点M条边的当今国际关系示意图。 作为两国友好关系的开端,两国之间需要进行「友好条约缔结会议」,以下简称会议。
如果某两个国家p和q要进行会议,那么需要一个向两国都派遣了大使的国家x作为中介。
会议结束后,会议的双方相互向对方的国家派遣大使。
换句话说,为了让国家p和国家q进行会议,必须存在一个国家x满足边(x,p)和边(x,q)都存在;
并且在会议后添加两条边(p,q)和(q,p)(如果需要添加的某条边已经存在则不添加)。
你的工作是对于可以进行会议的两国,选择会议的中介并促使会议进行。
使用这张图进行工作的模拟的话,世界距离和平还有多远的一个重要的基准就是这张图上的边数。 现在给出国家的个数以及当今国际关系的情报,请你求出反复选择两个国家,促使它们进行会议后,图上最多会有多少条边。 输入
第一行两个空格分隔的整数N和M,分别表示世界上国家的个数和图中的边数。
接下来M行描述画纸上的有向边的信息,其中第i行有两个空格分隔的整数ai和bi,表示图中有一条从ai到bi的有向边。 输出
输出一行一个整数,表示能实现的边数的最大值。
注意这个边数包括原有的边数和新连接的边数。

题目描述

样例输入

样例输出

样例解释
国家1作为中介国,国家2与3开会。
国家4作为中介国,国家3与5开会。
国家3作为中介国,国家2与5开会。

样例输入输出

数据范围:1≤N≤105,1≤M≤2×105,1≤ai,bi≤N,ai≠bi,(ai,bi)≠(aj,bj)

参考资料:

  [1]:http://icpc.upc.edu.cn/blog/?p=108

题意(摘抄自[1]):

  如果存在有向边<a,b>和<a,c>,就添加两条有向边<b,c>和<c,b>(已经存在就不添加),问最多有多少条边;

题解:

  昨天比赛做这道题的时候,想到了SCC,但我真的用SCC了,中间过程处理的不好(代码写搓了,逃)........

  今天晚上补这道题,看了看题解,和昨天自己想的差不多,就是代码实现上,[1]并没有用SCC知识用SCC思考这道题的做法;

  哎,欠缺的还是太多了,理解了将近半个小时,终于理解了,tql;

  下面谈谈我的进一步理解:

  (看会专业课先,理解明天写,下周要考两门,orz)

  对于某节点 u,如果 u 有 > 1 个儿子 v1,v,.......,vx,那么 v1,v,.......,vx  及其所有儿子可构成强连通;

  例如:

  

  节点①有两个儿子②③,那么②及其所有儿子④⑥,③及其所有儿子⑤构成强连通;

  即②③④⑤⑥构成强连通;

  同属于同一个强连通的所有节点的信息可以集中到一个节点上,假设这5个节点的信息集中到节点②上;

 int fa[maxn];///fa[i]:i所处的强连通的代表节点
ll tot[maxn];///tot[i]:i所处的强连通的个数,只有代表节点的tot[i]才有意义

  fa初始化为-1,tot初始化为1;

  对于上图,合并后的信息为:

  fa[2]=-1,fa[3,4,5,6]=2;

  tot[2]=5;(只有②节点的tot有用)

  那么,最重要的就是合并操作,具体如下:

 int Find(int x)///查找x所处的强连通的代表节点
{
return fa[x] == - ? x:fa[x]=Find(fa[x]);
}
void DFS(int u,int x)
{
for(int i=head[u];~i;i=G[i].next)
{
int y=G[i].to; y=Find(y);
if(x == y)
continue; fa[y]=x;
tot[x] += tot[y];
DFS(y,x);
}
} ///合并
bool update=true;
while(update)
{
update=false;
for(int u=;u <= n;++u)
{
///判断u是否已经处于某个强连通中
///如果u处于某个强连通中,x=u,反之x=-1
int x=tot[Find(u)] == ? -:u;
for(int i=head[u];~i;i=G[i].next)
{
/**
如果u不处于某个强连通中:
①如果其包含>1个儿子节点,其儿子节点可以构成强连通
如果u本身就处于某个强连通中:
①其所有儿子全部在这个强连通中
*/
int y=G[i].to;
if(x == -)
x=y;
else///将强连通中的节点信息合并到Find(x)中
{
x=Find(x);
y=Find(y); if(x == y)///在同一个强连通中
continue; update=true;
fa[y]=x;
tot[x] += tot[y];
DFS(y,x);///将y的所有儿子节点合并到Find(x)中
}
}
}
}

AC代码(偷偷换成了我的风格):

 #include<bits/stdc++.h>
using namespace std;
#define ll long long
#define memF(a,b,n) for(int i=0;i <= n;a[i]=b,++i);
const int maxn=1e5+; int n,m;
int num;
int head[maxn];
struct Edge
{
int to;
int next;
}G[maxn<<];
void addEdge(int u,int v)
{
G[num]={v,head[u]};
head[u]=num++;
}
int fa[maxn];///fa[i]:i所处的强连通的代表节点
ll tot[maxn];///tot[i]:i所处的强连通的个数,只有代表节点的tot[i]才有意义
int Find(int x)///查找x所处的强连通的代表节点
{
return fa[x] == - ? x:fa[x]=Find(fa[x]);
}
void DFS(int u,int x)
{
for(int i=head[u];~i;i=G[i].next)
{
int y=G[i].to; y=Find(y);
if(x == y)
continue; fa[y]=x;
tot[x] += tot[y];
DFS(y,x);
}
}
ll Solve()
{
memF(fa,-,n);
memF(tot,,n);
bool update=true;
while(update)
{
update=false;
for(int u=;u <= n;++u)
{
///判断u是否已经处于某个强连通中
///如果u处于某个强连通中,x=u,反之x=-1
int x=tot[Find(u)] == ? -:u;
for(int i=head[u];~i;i=G[i].next)
{
/**
如果u不处于某个强连通中:
①如果其包含>1个儿子节点,其儿子节点可以构成强连通
如果u本身就处于某个强连通中:
①其所有儿子全部在这个强连通中
*/
int y=G[i].to;
if(x == -)
x=y;
else///将强连通中的节点信息合并到Find(x)中
{
x=Find(x);
y=Find(y); if(x == y)///在同一个强连通中
continue; update=true;
fa[y]=x;
tot[x] += tot[y];
DFS(y,x);///将y的所有儿子节点合并到Find(x)中
}
}
}
} ll ans=;
for(int u=;u <= n;++u)
{
if(fa[u] == -)
ans += tot[u]*(tot[u]-);
for(int i=head[u];~i;i=G[i].next)
{
int x=Find(u);
int y=Find(G[i].to);
if(x != y)
ans++;
}
} return ans;
}
void Init()
{
num=;
memF(head,-,n);
}
int main()
{
scanf("%d%d",&n,&m);
Init();
for(int i=;i <= m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
}
printf("%lld\n",Solve()); return ;
}

JOISC2014 Day2 E "交朋友" (思维+假的SCC)的更多相关文章

  1. LOJ #2877. 「JOISC 2014 Day2」交朋友 并查集+BFS

    这种图论问题都挺考验小思维的. 首先,我们把从 $x$ 连出去两条边的都合并了. 然后再去合并从 $x$ 连出去一条原有边与一条新边的情况. 第一种情况直接枚举就行,第二种情况来一个多源 bfs 即可 ...

  2. POJ 1904 King's Quest(SCC的巧妙应用,思维题!!!,经典题)

    King's Quest Time Limit: 15000MS   Memory Limit: 65536K Total Submissions: 10305   Accepted: 3798 Ca ...

  3. zoj 4124 "Median" (思维?假的图论?)

    传送门 来源:2019 年“浪潮杯”第十届山东省 ACM 省赛 题意: 对于一个包含n个数的(n为奇数)序列val[ ],排序后的 val[ (n+1) / 2 ] 定义为 median: 有 n 个 ...

  4. 图论+思维(2019牛客国庆集训派对day2)

    题意:https://ac.nowcoder.com/acm/contest/1107/J n个点的完全图编号0-n-1,第i个点的权值为2^i,原先是先手选取一些边,然后后手选取一些点,满足先手选取 ...

  5. <每日一题> Day2:CodeForces-1141C.PolycarpRestoresPermutation(思维题)

    原题链接 参考代码: #include <iostream> #include <cstring> using namespace std; + , INF = 0x3f3f3 ...

  6. Spark机器学习 Day2 快速理解机器学习

    Spark机器学习 Day2 快速理解机器学习 有两个问题: 机器学习到底是什么. 大数据机器学习到底是什么. 机器学习到底是什么 人正常思维的过程是根据历史经验得出一定的规律,然后在当前情况下根据这 ...

  7. vue源码逐行注释分析+40多m的vue源码程序流程图思维导图 (diff部分待后续更新)

    vue源码业余时间差不多看了一年,以前在网上找帖子,发现很多帖子很零散,都是一部分一部分说,断章的很多,所以自己下定决定一行行看,经过自己坚持与努力,现在基本看完了,差ddf那部分,因为考虑到自己要换 ...

  8. 【NOIP 2017】Day2 T3 列队

    Problem Description \(Sylvia\) 是一个热爱学习的女孩子. 前段时间,\(Sylvia\) 参加了学校的军训.众所周知,军训的时候需要站方阵. \(Sylvia\) 所在的 ...

  9. 思维题练习专场-DP篇(附题表)

    转载请注明原文地址http://www.cnblogs.com/LadyLex/p/8536399.html 听说今年省选很可怕?刷题刷题刷题 省选已经结束了但是我们要继续刷题刷题刷题 目标是“有思维 ...

随机推荐

  1. 使用Data Lake Analytics从OSS清洗数据到AnalyticDB

    前提 必须是同一阿里云region的Data Lake Analytics(DLA)到AnalyticDB的才能进行清洗操作: 开通并初始化了该region的DLA服务: 开通并购买了Analytic ...

  2. JavaScript--轮播图_带计时器

    轮播图效果: 实现的功能: 1.鼠标移入,左右按钮显示 2.右下叫小圆点鼠标移入,进入下一张图 3.左右按钮点击,右下小圆点页跟随变更 4.自动开启计时器,鼠标移入右下叫小圆点区,计时器停止,鼠标移出 ...

  3. phpcms url路由规则、多站点、PC手机切换

    解决一个分站点pc手机共存的问题 首先需要有PC手机两套模板.通过修改url路由规则,在同一目录下生成PC手机两套静态网站,PC使用默认url路由规则,手机端使用文件名追加“_m”的路由规则. 然后通 ...

  4. sqlite数据库文件导入到sqlserver 2016-03-26 21:55 1292人阅读 评论(1) 收藏

    最近在公司做项目,需要做两个版本,都是cs的,然后要求是一个单机版,自带数据库,另一个要进行局域网内的连接,所以公司的大牛设计是,局域网版的用sqlserver2008,单机版的则用sqlite.然后 ...

  5. Auto CAD 安装问题 “acad.exe - 系统错误 ”

    Auto CAD 安装不上,提示“cad装不上 提示无法启动此程序,因为计算机中丢失 ac1st16.dll” 解决方法: 我的电脑——>右键 属性——>高级选项卡(win7的是高级系统设 ...

  6. MySQL按时间统计每个小时记录数

    MySQL按时间统计每个小时记录数 方案1: ? 1 2 3 4 5 6 7 SELECT  @rownum := @rownum + 1 AS ID,         CONCAT((CASE WH ...

  7. AIDL基本用法

    1. AIDL有什么用?用TA到目的是什么? 2. 怎么用AIDL? 1. AIDL有什么用? 1.1. 为了提高代码执行速度,将部分逻辑封入C/C++代码中  1.2. 为了调用这部分代码,使用JN ...

  8. oracle函数 DUMP(w[,x[,y[,z]]])

    [功能]返回数据类型.字节长度和在内部的存储位置. [参数] w为各种类型的字符串(如字符型.数值型.日期型……) x为返回位置用什么方式表达,可为:8,10,16或17,分别表示:8/10/16进制 ...

  9. oracle函数 LTRIM(c1,[,c2])

    [功能]删除左边出现的字符串 [参数]C1 字符串 c2 追加字符串,默认为空格 [返回]字符型 [示例] SQL> select LTRIM('   gao qian jing',' ') t ...

  10. Spark Steaming消费kafka数据条数变少问题

    对于基于Receiver 形式,我们可以通过配置 spark.streaming.receiver.maxRate 参数来限制每个 receiver 每秒最大可以接收的记录的数据:对于 Direct ...