第一次做出来黑题祭

虽然感觉难度其实并不到黑题的难度

题解:

其实这道题并没用什么特别的知识,只是Tarjan求双联通分量和LCA的结合。

所以,我们可以很显然的发现(如此恶劣的词汇,逃

这道题其实就是给你一个无向图,其中一个点双联通分量算作一个点,询问两个点之间(包括这两个点)有多少点(注意重边不需要缩点)。注意这里的图是无向图,所以我们如果用单纯的Tarjan求强连通分量,就会得到WA的好成绩。

因此 --->我们用Tarjan双联同分量进行缩点,特判一下如果是他的父亲,就不执行(去除重边的影响),然后\(O(m)\)重建图,跑一边LCA求距离就好了

这里有坑:

1.没有关注重边。

2.查询写成原图中的编号,应为所在联通块的编号。

3.数据略卡常,要用快读进行输入。

CODE:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack> using namespace std; #define N 10010
#define M 100010 int head[N],dfn[N],low[N];
int idx,link[N],tot1,fa[N][25];
int belong[N],m,n,tot2;
int depth[N],xx[M],yy[M];
bool vis[N];
stack<int> st;
struct Edge{
int from,to;
}e[M*2],edge[M*2]; 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;
}
inline void add_edge(int u,int v) {
e[++tot1].from = v;
e[tot1].to = head[u];
head[u] = tot1;
}
int cnt;
void Tarjan(int u,int from) {
low[u] = dfn[u] = ++idx;
st.push(u);
vis[u] = true;
for(int i = head[u] ; i ; i = e[i].to) {
int v = e[i].from;
if(v == from) continue;
if(dfn[v] == -1) {
Tarjan(v,u);
low[u] = min(low[u],low[v]);
} else if(vis[v])
low[u] = min(low[u],dfn[v]);
}
if(dfn[u] == low[u]) {
++cnt;
while(1){
int v = st.top();
st.pop();
vis[v] = 0;
belong[v]=cnt;
if(v == u) break;
}
}
}
inline void add_edge2(int u,int v) {
edge[++tot2].from = v;
edge[tot2].to = link[u];
link[u] = tot2;
}
void dfs(int u,int from,int deepth) {
depth[u] = deepth;
fa[u][0] = from;
for(int i = link[u] ; i ; i = edge[i].to) {
int v = edge[i].from;
if(v != from) dfs(v,u,deepth+1);
}
}
int LCA(int u,int v) {
if(depth[u] < depth[v]) swap(u,v);
for(int j = 0 ; j <= 22 ; j++)
if((depth[u] - depth[v]) & (1<<j))
u = fa[u][j];
if(u == v) return u;
for(int i = 22 ; i >= 0 ; i--)
if(fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
return fa[u][0];
}
int ans[28000];
int print(int n) {
int cur =0;
if(n == 0) { cout<<'0';return 0; }
if(n < 0) { putchar('-');n=0-n; }
while(n) {
int p = n % 2;
ans[++cur] = p;
n /= 2;
}
for(int i = cur ; i >= 1 ; i--)
printf("%d",ans[i]);
cout<<endl;
} int main() {
n = read();
m = read();
memset(dfn,-1,sizeof(dfn) );
memset(low,-1,sizeof(low) );
for(int i = 1 ; i <= m ; i++) {
int u,v;
u= read(),v = read();
xx[i] = u,yy[i] = v;
add_edge(u,v);
add_edge(v,u);
}
for(int i = 1 ; i <= n ; i++)
if(dfn[i] == -1)
Tarjan(i,-1);
for(int i = 1 ; i <= m ; i++) {
if(belong[xx[i]] != belong[yy[i]]) {
add_edge2(belong[xx[i]],belong[yy[i]]);
add_edge2(belong[yy[i]],belong[xx[i]]);
}
}
dfs(belong[1],belong[1],0);
for(int j = 1 ; j <= 22 ; j++)
for(int i = 1 ; i <= cnt ; i++)
fa[i][j] = fa[fa[i][j - 1]][j - 1];
int T;
T = read();
while(T--) {
int u,v;
scanf("%d%d",&u,&v);
int num = LCA(belong[u],belong[v]);
print(depth[belong[u]] + depth[belong[v]] - depth[num] - depth[num] + 1);
}
return 0;
}

[洛谷P2783]有机化学之神偶尔会做作弊的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. [luogu2783] 有机化学之神偶尔会做作弊

    题目链接 洛谷. Solution 边双缩点然后\(lca\)跑\(dis\)就好了. 注意这里是边双,不知道为啥所有题解都说的是点双. 边双是定义在点上的,即每个点只属于一个边双:点双是定义在边上的 ...

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

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

随机推荐

  1. 解题:HEOI 2013 SAO

    题面 不好讲,直接上式子吧=.= 设$dp[i][j]$表示考虑完$i$的子树后$i$的排名为$j$的方案数,然后转移类似树形背包,具体来说是(这里假设子树在$i$后选,其实反过来还用这个式子答案也是 ...

  2. iterm2切换显示屏vim乱行解决

    http://note.youdao.com/noteshare?id=5aec9d82cc3a95b6909e9966b4aa3227

  3. redhat6下安装centos的yum源

    因为redhat中的yum是收费的,未注册时不允许使用的,下面是挂载光盘后的情况,未挂载是没有yum命令.但是下面即便挂载了也是需要验证的 [root@localhost /]# yum instal ...

  4. LazyMay:实现同步和异步任务的顺序执行

    在掘金看到的文章,流程控制同步和异步任务的顺序执行,收益匪浅,工作中能用到. 1.实现以下效果 实现一个LazyMan,可以按照以下方式调用: LazyMan(“Hank”)输出: Hi! This ...

  5. vsCode开发java遇到的问题整理、解决方案(持续更新)

    获取控制台输入的信息: 休息launch.json文件中的console属性internalConsole(内部控制台)修改为externalTerminal(外部控制台)即可正常获取输入信息,代码如 ...

  6. [USACO5.3]量取牛奶Milk Measuring

    https://daniu.luogu.org/problemnew/show/P2744 滚动数组压去第一维:前i种木桶 f[j] 量取体积j最少需要几种木桶 g[j]  体积j的最优解是否使用了第 ...

  7. appium 使用过程问题踩坑-笔记

    问题1:虚拟设备选用问题 运行脚本抛出异常,创建session对象失败 排查过程:在进入cmd模式下: ①adb devices   --ok ②appium-doctor  --ok ③appium ...

  8. HIIT训练第一波,值得收藏的训练计划

    下面这三套训练,收藏好,平时在家或者出差都能用! 即使你是一个健身新手,也并不意味着高强度间歇训练(HIIT)不适合你. 这种快节奏的训练已经显露出短时间内燃烧成吨卡路里的能力.所以,你并不需要再健身 ...

  9. IFrame跨域处理方法-Javascript

    在漫长的前端开发旅途上,无可避免的会接触到ajax,而且一般情况下都是用在同一域下的ajax请求:但是如果请求是发生在不同的域下,请求就无法执行,并且会抛出异常提示不允许跨域请求,目前我没有找到明确的 ...

  10. Spark MLlib使用有感

    这些天在公司里面做文本分析的任务,我跟着玻哥一起做,先研究了算法的可行度,最后决定使用Google的Word2Vector和LDA算法来对文本进行分析.之前因为看过一些Spark的东西,所以准备瞄准M ...