传送门

题目描述
你是活跃在历史幕后的一名特工,为了世界和平而夜以继日地努力着。
这个世界有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. Leetcode762.Prime Number of Set Bits in Binary Representation二进制表示中质数个计算置位

    给定两个整数 L 和 R ,找到闭区间 [L, R] 范围内,计算置位位数为质数的整数个数. (注意,计算置位代表二进制表示中1的个数.例如 21 的二进制表示 10101 有 3 个计算置位.还有, ...

  2. typeof与js数据类型

    js有6种数据类型有null.undefied.string.number.boolean.object. 然而我之前的[误区]: typeof的返回值和JS的数据类型是一样的.但是并不是(⊙o⊙)哦 ...

  3. log4j日志系统

    在项目开发中,记录错误日志是一个很有必要功能.一是方便调试:二是便于发现系统运行过程中的错误:三是存储业务数据,便于后期分析: 在java中,记录日志,有很多种方式. 比如,自己实现. 自己写类,将日 ...

  4. 自己动手写js分享插件 [支持https] (QQ空间,微信,新浪微博。。。)

    转载:https://blog.csdn.net/libin_1/article/details/52424340 废话不多说,传送门:http://download.csdn.net/detail/ ...

  5. SQLServer —— 变量的使用

    一.局部变量的定义与赋值 定义语法: -- 声明一个局部变量 DECLARE @变量名 数据类型 -- 声明多个局部变量 DECLARE @变量名1 数据类型1, @变量名2 数据类型2 赋值语法: ...

  6. springmvc restful风格操作

    ssm框架 controller: package com.sgcc.controller; import java.util.ArrayList; import java.util.List; im ...

  7. AtCoder Regular Contest 085 C HSI【概率论】

    AtCoder Regular Contest 085 C HSI 没学概率论还不怎么看得懂,虽然感觉不难,其实明明可以猜出来的..... 参考博客:https://www.cnblogs.com/g ...

  8. ffmpeg在iOS的使用 - iFrameExtractor源码解析

    http://www.cocoachina.com/ios/20150914/13284.html iFrameExtractor地址:https://github.com/lajos/iFrameE ...

  9. IO流之字符流-1

    Reader和Writer抽象类 Reader是定义java的流式字符输入流模式的抽象类 Writer是定义流式字符输出的抽象类 该类的方法都返回void值并在错条件下抛出IOException异常 ...

  10. oracle函数 to_single_byte(c1)

    [功能]将字符串中的全角转化为半角 [参数]c1,字符型 [返回]字符串 [示例] SQL> select to_multi_byte('高A') text from dual; test -- ...