题面

前言

这道题以前还是道(水)黑题,现在怎么降紫了????

前置芝士

  1. tarjain 缩点

  2. 倍增求LCA或树剖求LCA

  3. 脑子。。。

题意

给你一个无向图,要求你把所有的环缩成一个点。在新得到的图上问你两个点之间有多少个点。

分析

首先我们会由 "所有的环状碳都变成了一个碳" 想到要缩点。

但是无向图怎么缩点呢?

我们可以按照原来无向图那样缩点,但要注意的一点是 $to != fa[x] $

因为这是无向图,可能有的边会直接连向他父亲,假如我们要走这条边的话,就会重

复搜,就这样一直无限循环下去。剩下的就和有向图的缩点没什么区别了。

接着我们就要考虑每个询问。

我们把所有的环去掉后,就会得到一个有向无环图(树)。不理解的童鞋请画图自证

那么问题就会转化为树上问题。

甩给你一张图

假如我们要求 \(4\) 和 \(7\) 之间的有多少个点。我么可以用

\(dep[4] + dep[7] - 2 * dep[3]\) + 1

即 \(dep[x] + dep[y] - 2 * dep[lca(x,y)] + 1\)

由于他的深度有类似于前缀和的性质,所以我们可以这么处理。

为什么要减一呢? 因为你 $LCA $处 只能算一个点,但你却减了两次,所以要

重新加上

补充

关于一个数转二进制的方法。

我们可以联想到快速幂中要依次取出指数的二进制每一位,所以我们可以像快速幂

中的写法模拟出二进制每一位。

代码如下

void shuchu(int x)
{
int xx = 0;//记录有多少位
for(; x; x>>=1)//依次取出每一位上的数字
{
xx++;
if(x & 1) t[xx] = 1;
else t[xx] = 0;
}
for (int i = xx; i >= 1; i-- ) printf("%d",t[i]);//倒序输出
printf("\n");
}

几个要注意的点

  1. 求两个点的LCA 一定要在新建的图上求 (本蒟蒻就在这里卡了好几回)

  2. 树剖求 LCA 时要注意是在缩完点之后的图上求

  3. tarjain 缩点时要注意不能访问到他父亲的边

不懂得同鞋 , 请看下面代码 ,下面有注释。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5+10;
int n,m,u,v,x,y,tot,sum,cnt,num,topp,T;
int dep[N],fa[N],size[N],top[N],head[N],hed[N];
int shu[N],dfn[N],low[N],sta[N],son[N];
int t[N];
bool vis[N];
inline int read()//标准快读
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
return s * w;
}
struct node{int to,net;}e[N<<1],edge[N<<1];//为了压行不择手段
void add(int x,int y)
{
e[++tot].to = y;
e[tot].net = head[x];
head[x] = tot;
}
void add_(int x,int y)//建新图上的边
{
edge[++sum].to = y;
edge[sum].net = hed[x];
hed[x] = sum;
}
void tarjain(int x,int fa)//缩点
{
dfn[x] = low[x] = num++;
sta[++topp] = x; vis[x] = 1;
for(int i = head[x]; i; i = e[i].net)
{
int to = e[i].to;
if(to == fa) continue;//特判是不是联向他父亲得边
if(!dfn[to])
{
tarjain(to,x);
low[x] = min(low[x],low[to]);
}
else if(vis[to])
{
low[x] = min(low[x],dfn[to]);
}
}
if(dfn[x] == low[x])//求强联通分量
{
cnt++; int y;
do
{
y = sta[topp--];
//size[cnt]++;
shu[y] = cnt;
vis[y] = 0;
}while(x != y);
}
}
void get_tree(int x)//树剖第一遍DFS求重儿子
{
dep[x] = dep[fa[x]] + 1; size[x] = 1;
for(int i = hed[x]; i; i = edge[i].net)
{
int to = edge[i].to;
if(to == fa[x]) continue;
fa[to] = x;
get_tree(to);
size[x] += size[to];
if(size[son[x]] > size[to]) son[x] = to;
}
}
void dfs(int x,int topp)//树剖第二遍DFS求每条链的顶端
{
top[x] = topp;
if(son[x]) dfs(son[x],topp);
for(int i = hed[x]; i; i = edge[i].net)
{
int to = edge[i].to;
if(to == fa[x] || to == son[x]) continue;
dfs(to,to);
}
}
int lca(int x,int y)//树剖求LCA
{
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x,y);
x = fa[top[x]];
}
if(dep[x] < dep[y]) return x;
else return y;
}
void shuchu(int x)//二进制转化
{
int xx = 0;
for(; x; x>>=1)
{
xx++;
if(x & 1) t[xx] = 1;
else t[xx] = 0;
}
for (int i = xx; i >= 1; i--) printf("%d",t[i]);
printf("\n");
}
int main()
{
n = read(); m = read();
for(int i = 1; i <= m; i++)
{
u = read(); v = read();
add(u,v); add(v,u);
}
for(int i = 1; i <= n; i++)
{
if(!dfn[i]) tarjain(i,0);
}
for(int i = 1; i <= n; i++)//缩点
{
for(int j = head[i]; j; j = e[j].net)
{
int to = e[j].to;
if(shu[to] != shu[i])
{
add_(shu[i],shu[to]);
}
}
}
get_tree(1);
dfs(1,1);
T = read();
while(T--)
{
x = read(); y = read();
int Lca = lca(shu[x],shu[y]);
int ans = dep[shu[x]] + dep[shu[y]] - 2 * dep[Lca] + 1;//计算每个询问的答案
shuchu(ans);
}
return 0;
}

P2783 有机化学之神偶尔也会作弊 题解的更多相关文章

  1. 洛谷 P2783 有机化学之神偶尔会做作弊 解题报告

    P2783 有机化学之神偶尔会做作弊 题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹. 然而你的化竞基友却向你求助了. &quo ...

  2. 【题解】Luogu P2783 有机化学之神偶尔会做作弊

    原题链接:P2783 有机化学之神偶尔会做作弊 一看,是黑题,太毒瘤了,不写 什么单链??! 只会画有机化学中正六边形的我觉得这样不行QAQ(我才初二) 当然,题目也给你了详细的解释 实际呢,这道题先 ...

  3. luogu P2783 有机化学之神偶尔会做作弊 |Tarjan+LCA

    题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹. 然而你的化竞基友却向你求助了. "第1354题怎么做"&l ...

  4. 洛谷 P2783 有机化学之神偶尔会做作弊(Tarjan,LCA)

    题目背景 LS中学化学竞赛组教练是一个酷爱炉石的人. 有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹. 然而你的化竞基友却向你求助了. “第1354题怎么做”<--手语 他问道 ...

  5. LuoGu P2783 有机化学之神偶尔会做作弊

    题目传送门 人生第一道黑题呢,虽然这题是黑题中的水题并且我调了一整节课,但是我还是很兴奋啊.毕竟人生第一道黑题啊 这个题根据题意,先把整个图进行tarjan缩点,建出一棵树,对于每一组询问,两点之间的 ...

  6. [洛谷P2783]有机化学之神偶尔会做作弊

    第一次做出来黑题祭 虽然感觉难度其实并不到黑题的难度 题解: 其实这道题并没用什么特别的知识,只是Tarjan求双联通分量和LCA的结合. 所以,我们可以很显然的发现(如此恶劣的词汇,逃 这道题其实就 ...

  7. Tarjan+LCA【洛谷P2783】 有机化学之神偶尔会做作弊

    [洛谷P2783] 有机化学之神偶尔会做作弊 题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹. 然而你的化竞基友却向你求助了. ...

  8. 【洛谷 P2783】 有机化学之神偶尔会做作弊 (双联通分量)

    题目链接 可能是除了<概率论>的最水的黑题了吧 用\(Tarjan\)缩点(点双联通分量),然后就是树上两点之间的距离了,跑\(LCA\)就好了. #include <cstdio& ...

  9. 洛谷P2783 有机化学之神偶尔会作弊

    题目传送门 啦啦啦,发个文纪念一下第一道在洛谷上A的黑题,一次性就过真是无比舒服-(虽然某些大佬说这题有点水……)题目其实思路不难,Tarjan缩点+LCA,不过因为是无向边,所以在Tarjan的时候 ...

随机推荐

  1. T4m

    Unity T4M 中文讲解 http://blog.csdn.net/tianmao111/article/details/46482963

  2. [MRCTF]Web WriteUp

    和武科大WUSTCTF同时打的一场比赛,最后因为精力放在武科大比赛上了,排名13  - -Web题目难度跨度过大,分不清层次,感觉Web题目分布不是很好,质量还是不错的 Ez_bypass 进入题目得 ...

  3. js判断一个字符串中出现次数最多的字符及次数

    最近面试总是刷到这个题,然后第一次的话思路很乱,这个是我个人思路 for循环里两个 if 判断还可以优化 var maxLength = 0; var maxStr = ''; var count = ...

  4. Sentinel使用

    Sentinel控制台的功能主要包括:流量控制.降级控制.热点配置.系统规则和授权规则等 # 安装sentinel的控制台 ## 下载地址 Sentinel控制台下载地址: https://githu ...

  5. Python - 网易邮箱邮件阅读和删除辅助小脚本

    摘要:[原创]转载请注明作者Johnthegreat和本文链接 简介:在Windows下的网易邮箱大师客户端中,阅读邮件时,可以使用快捷键Delete删除邮件,然后自动跳到下一封,如果再按一次Dele ...

  6. selenium做UI自动化时,模拟鼠标各种操作的ActionChains的用法

    1.selenium做自动化的时候,需要模拟鼠标进行单击.双击.右键.拖拽等操作,selenium提供了ActionChains类来进行处理. 2.执行原理:当你调用ActionChains的方法时, ...

  7. 第3课 - makefile伪目标的引入

    第3课 - makefile伪目标的引入 1. makefile 中的目标究竟是什么? (1)默认情况下,make 认为目标对应着一个文件  ==>  目标即文件名 (2)make 首先会检测目 ...

  8. [LeetCode]66. 加一(数组)

    ###题目 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示例 ...

  9. 分布式系统监视zabbix讲解三之用户和用户组

    概述 Zabbix 中的所有用户都通过 Web 前端去访问 Zabbix 应用程序.并为每个用户分配唯一的登陆名和密码. 所有用户的密码都被加密并储存于 Zabbix 数据库中.用户不能使用其用户名和 ...

  10. ant在windows环境下安装

    前言: Apache Ant,是一个将软件编译.测试.部署等步骤联系在一起加以自动化的一个工具,大多用于 Java 环境中的软件开发. 举个例子说明:平时在写 Java 程序的时候,基本的步骤都是 打 ...