【洛谷 P2783】 有机化学之神偶尔会做作弊 (双联通分量)
2024-08-27 22:51:26
题目链接
可能是除了《概率论》的最水的黑题了吧
用\(Tarjan\)缩点(点双联通分量),然后就是树上两点之间的距离了,跑\(LCA\)就好了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int s; char ch;
inline int read(){
s = 0; ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
return s;
}
const int MAXN = 10010;
const int MAXM = 50010;
int dfn[MAXN], low[MAXN], id, bridge[MAXM << 1], dcc, belong[MAXN], top, vis[MAXN];
int n, m, a, b, head[MAXN], num = 1, f[MAXN][20], dep[MAXN], t, stack[MAXN];
struct Edge{
int from, next, to;
}e[MAXM << 2];
inline void Add(int from, int to){
e[++num].to = to; e[num].from = from; e[num].next = head[from]; head[from] = num;
e[++num].to = from; e[num].from = to; e[num].next = head[to]; head[to] = num;
}
void Tarjan(int u, int fa){
dfn[u] = low[u] = ++id; stack[++top] = u; vis[u] = 1;
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
if(!dfn[e[i].to]){
Tarjan(e[i].to, u);
low[u] = min(low[u], low[e[i].to]);
}
else if(vis[e[i].to])
low[u] = min(low[u], dfn[e[i].to]);
if(dfn[u] == low[u]){
++dcc;
do
belong[stack[top]] = dcc;
while(stack[top--] != u);
}
}
void getDF(int u, int fa){
f[u][0] = fa; dep[u] = dep[fa] + 1;
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
getDF(e[i].to, u);
}
int LCA(int u, int v){
if(dep[u] < dep[v]) swap(u, v);
int cha = dep[u] - dep[v];
if(cha)
for(int i = 0; i <= 18; ++i)
if((cha >> i) & 1)
u = f[u][i];
if(u != v){
for(int i = 18; ~i; --i)
if(f[u][i] != f[v][i])
u = f[u][i], v = f[v][i];
return f[u][0];
}
return u;
}
int dis(int u, int v){
return dep[u] + dep[v] - (dep[LCA(u, v)] << 1) + 1;
}
void print(int x){
if(x > 1) print(x >> 1);
printf("%d", x & 1);
}
int main(){
n = read(); m = read();
for(int i = 1; i <= m; ++i)
Add(read(), read());
for(int i = 1; i <= n; ++i)
if(!dfn[i])
Tarjan(i, 0);
memset(head, 0, sizeof head);
int tmp = num;
for(int i = 2; i <= tmp; i += 2)
if(belong[e[i].from] != belong[e[i].to])
Add(belong[e[i].from], belong[e[i].to]);
getDF(1, 0);
for(int j = 1; j <= 18; ++j)
for(int i = 1; i <= dcc; ++i)
f[i][j] = f[f[i][j - 1]][j - 1];
t = read();
while(t--) print(dis(belong[read()], belong[read()])), puts("");
return 0;
}
最新文章
- chrome经常崩溃解决过程
- Java Se :线性表
- Jmeter组件4. Regular Expression Extractor
- TeeChart中 Line的Clear方法
- 微信 关闭手机微信内置浏览器的js
- ios 7 20像素解决
- 调试技巧 —— 如何利用windbg + dump + map分析程序异常
- 通过PHP连接MYSQL数据库 创建数据库 创建表
- IE 将“通过域访问数据源”设置为启用(注册表)
- mysql在linux的安装
- 输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数
- Tornado 网站demo 一
- shell 排除目录
- JS学习小结(上)
- Codeforces 868D Huge Strings - 位运算 - 暴力
- linux中eth0原何变成了eth1
- 绕过限制,在PC上调试微信手机页面
- Token机制,防止web页面重复提交
- sklearn 中的交叉验证
- history统计命令最多的20条
热门文章
- LintCode-66.二叉树的前序遍历
- TCP系列25—重传—15、DSACK虚假重传探测
- SQL SERVER技术内幕之10 可编程对象
- C#中Console.ReadLine()和Console.Read()有何区别?
- Flink中的数据传输与背压
- centos7 nginx端口转发出现502的其中一种原因
- BZOJ 1022 小约翰的游戏(anti-sg)
- P2845 [USACO15DEC]Switching on the Lights 开关灯
- 【以前的空间】BIT的两个小小运用
- 运动员最佳匹配问题 KM算法:带权二分图匹配