HDU 3686 Traffic Real Time Query System(点双连通)
题意
给定一张 \(n\) 个点 \(m\) 条边的无向图,\(q\) 次询问,每次询问两边之间的必经之点个数。
思路
求两点之间必经之边的个数用的是边双缩点,再求树上距离。而对比边双和点双之后,我们不难发现点和边之间的对应关系,边双分量和点双分量的性质很多都是对称的。
边双 | 点双 |
---|---|
两点之间至少有两条不共边的路径 | 两边之间至少有两条不共点的路径 |
边双间由桥边连接 | 点双内没有割点 |
边双间由桥边连接 | 点双间由割点连接 |
另外,一个点双也是一个特殊的边双,就像一个点仙人掌是一个特殊的边仙人掌一样。
那就容易看出本题就是一个点双缩点的裸题了。把所有的割点和点双分量拿出来,让每一个割点向它所在的点双分量连边即可。可能把图“缩成树”这种事本来就适合边双干,点双写起来不是很自然,也没什么办法。
代码
#include<bits/stdc++.h>
#define FOR(i, x, y) for(int i = (x), i##END = (y); i <= i##END; ++i)
#define DOR(i, x, y) for(int i = (x), i##END = (y); i >= i##END; --i)
template<typename T, typename _T> inline bool chk_min(T &x, const _T &y) {return y < x ? x = y, 1 : 0;}
template<typename T, typename _T> inline bool chk_max(T &x, const _T &y) {return x < y ? x = y, 1 : 0;}
typedef long long ll;
const int N = 10005;
const int M = 100005;
template<const int N, const int M, typename T> struct Linked_List
{
int head[N], nxt[M], tot; T to[M];
Linked_List() {clear();}
T &operator [](const int x) {return to[x];}
void clear() {memset(head, -1, sizeof(head)), tot = 0;}
void add(int u, T v) {to[tot] = v, nxt[tot] = head[u], head[u] = tot++;}
#define EOR(i, G, u) for(int i = G.head[u]; ~i; i = G.nxt[i])
};
Linked_List<N, M << 1, int> G;
Linked_List<N << 1, N << 2, int> T;
int dfn[N], low[N], stk[M], bel[M], dfn_idx, bcc, tp, tot;
bool mark[M];
int fa[N << 1], dep[N << 1], sz[N << 1], son[N << 1], top[N << 1];
int n, m, q;
void tarjan(int u, int fa_e)
{
dfn[u] = low[u] = ++dfn_idx;
EOR(i, G, u)
{
if(i == (fa_e ^ 1)) continue;
int v = G[i];
if(!dfn[v])
{
stk[++tp] = i;
tarjan(v, i), chk_min(low[u], low[v]);
if(low[v] >= dfn[u])
{
bcc++;
do bel[stk[tp] / 2] = bcc;
while(stk[tp--] != i);
}
}
else if(dfn[v] < dfn[u])
{
stk[++tp] = i;
chk_min(low[u], dfn[v]);
}
}
}
void dfs(int u, int f, int d)
{
fa[u] = f, dep[u] = d, sz[u] = 1, son[u] = 0;
EOR(i, T, u)
{
int v = T[i];
if(v == f) continue;
dfs(v, u, d + 1);
sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
void hld(int u, int tp)
{
top[u] = tp;
if(son[u]) hld(son[u], tp);
EOR(i, T, u)
{
int v = T[i];
if(v == fa[u] || v == son[u]) continue;
hld(v, v);
}
}
int get_lca(int u, int v)
{
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]]) std::swap(u, v);
u = fa[top[u]];
}
return dep[u] < dep[v] ? u : v;
}
int get_dis(int u, int v)
{
int lca = get_lca(u, v);
return dep[u] + dep[v] - 2 * dep[lca];
}
int main()
{
while(scanf("%d%d", &n, &m), (n || m))
{
G.tot = T.tot = 0;
FOR(i, 1, n) G.head[i] = -1, dfn[i] = 0;
FOR(i, 1, 2 * n) T.head[i] = -1, dep[i] = 0;
bcc = dfn_idx = tp = 0;
FOR(i, 1, m)
{
int u, v;
scanf("%d%d", &u, &v);
G.add(u, v), G.add(v, u);
}
FOR(i, 1, n) if(!dfn[i]) tarjan(i, -1);
tot = bcc;
FOR(u, 1, n)
{
tp = 0;
EOR(i, G, u)
{
if(!mark[bel[i / 2]])
{
mark[bel[i / 2]] = 1;
stk[++tp] = bel[i / 2];
}
}
if(tp >= 2)
{
tot++;
FOR(i, 1, tp) T.add(tot, stk[i]), T.add(stk[i], tot);
}
while(tp) mark[stk[tp]] = 0, tp--;
}
FOR(i, 1, tot) if(!dep[i]) dfs(i, 0, 1), hld(i, i);
scanf("%d", &q);
while(q--)
{
int e1, e2;
scanf("%d%d", &e1, &e2);
e1--, e2--;
printf("%d\n", get_dis(bel[e1], bel[e2]) / 2);
}
}
return 0;
}
HDU 3686 Traffic Real Time Query System(点双连通)的更多相关文章
- HDU 3686 Traffic Real Time Query System(双连通分量缩点+LCA)(2010 Asia Hangzhou Regional Contest)
Problem Description City C is really a nightmare of all drivers for its traffic jams. To solve the t ...
- hdu 3686 Traffic Real Time Query System 点双两通分量 + LCA。这题有重边!!!
http://acm.hdu.edu.cn/showproblem.php?pid=3686 我要把这题记录下来. 一直wa. 自己生成数据都是AC的.现在还是wa.留坑. 我感觉我现在倒下去床上就能 ...
- HDU 3686 Traffic Real Time Query System (图论)
HDU 3686 Traffic Real Time Query System 题目大意 给一个N个点M条边的无向图,然后有Q个询问X,Y,问第X边到第Y边必需要经过的点有多少个. solution ...
- 【HDOJ】3686 Traffic Real Time Query System
这题做了几个小时,基本思路肯定是求两点路径中的割点数目,思路是tarjan缩点,然后以割点和连通块作为新节点见图.转化为lca求解.结合点——双连通分量与LCA. /* 3686 */ #includ ...
- 【Targan+LCA】HDU 3686 Traffic Real Time Query
题目内容 洛谷链接 给出一个\(n\)个节点,\(m\)条边的无向图和两个节点\(s\)和\(t\),问这两个节点的路径中有几个点必须经过. 输入格式 第一行是\(n\)和\(m\). 接下来\(m\ ...
- CH#24C 逃不掉的路 和 HDU3686 Traffic Real Time Query System
逃不掉的路 CH Round #24 - 三体杯 Round #1 题目描述 现代社会,路是必不可少的.任意两个城镇都有路相连,而且往往不止一条.但有些路连年被各种XXOO,走着很不爽.按理说条条大路 ...
- HDU Traffic Real Time Query System
题目大意是:对于(n, m)的图,给定边a, b查询从a到b要经过的割点的最少数目. 先tarjan算法求双连通然后缩点,即对于每个割点将周围的每个双连通看成一个点与之相连.然后求解LCA即可,距离d ...
- HDU3686 Traffic Real Time Query System 题解
题目 City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, t ...
- Traffic Real Time Query System 圆方树+LCA
题目描述 City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, ...
随机推荐
- ubuntu18.04.2下编译openjdk9源码
最近在看<深入理解Java虚拟机 第二版>这本书,上面有关于自己编译OpenJDK源码的内容.自己根据书里的指示去操作,花了三天的时间,重装了好几次Ubuntu(还不知道快照这个功能,好傻 ...
- Window权限维持(九):端口监视器
后台打印程序服务负责管理Windows操作系统中的打印作业.与服务的交互通过打印后台处理程序API执行,该API包含一个函数(AddMonitor),可用于安装本地端口监视器并连接配置.数据和监视器文 ...
- java的递归异常—一个异常可能由另一个异常触发
关键字: Caused by nested exception java.lang.reflect.InvocationTargetException: null at sun.reflect.Nat ...
- SpringBoot自定义注解、AOP打印日志
前言 在SpringBoot中使用自定义注解.aop切面打印web请求日志.主要是想把controller的每个request请求日志收集起来,调用接口.执行时间.返回值这几个重要的信息存储到数据库里 ...
- Java引用类型原理深度剖析,看完文章,90%的人都收藏了
本文为synchronized系列第二篇.主要内容为分析偏向锁的实现. 偏向锁的诞生背景和基本原理在上文中已经讲过了. 本文将分为几块内容: 1.偏向锁的入口 2.偏向锁的获取流程 3.偏向锁的撤销流 ...
- Linux目录和文件——目录格式
Linux目录和文件——目录格式 摘要:本文主要了解了Linux系统的目录格式. 一切皆文件 Linux下“一切皆文件”是Unix/Linux的基本哲学之一. Linux中所有内容都是以文件的形式保存 ...
- 【IPHONE开发-OBJECTC入门学习】文件的操作,读写复制文件
转自:http://blog.csdn.net/java886o/article/details/9041547 FileTools.h FileTools.m #import "FileT ...
- 图解Java数据结构之单链表
本篇文章介绍数据结构中的单链表. 链表(Linked List)介绍 链表可分为三类: 单链表 双向链表 循环列表 下面具体分析三个链表的应用. 单链表 链表是有序的列表,它在内存中存储方式如下: 虽 ...
- LCD RGB 控制技术讲解 — 时钟篇(上)【转】
1. 时序图 下面是LCD RGB 控制的典型时序图 天啊,一下就上这玩意,怎么看??? 其实要解释上面的时序图,我们还需要了解一些LCD的显示过程.所以现在只是有个印象,稍后我们详细讲解. 2. L ...
- springboot项目打成jar包后台运行在linux上
背景:springboot2为为主体搭建的项目,直接打成jar包,上传到linux上面 启动项目:java -jar xx.jar 这样很方便,但是不能关闭窗口,否则项目就停了 后台启动: nohup ...