HDU3686 Traffic Real Time Query【缩点+lca】
题目
City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, the mayor plans to build a RTQS (Real Time Query System) to monitor all traffic situations. City C is made up of N crossings and M roads, and each road connects two crossings. All roads are bidirectional. One of the important tasks of RTQS is to answer some queries about route-choice problem. Specifically, the task is to find the crossings which a driver MUST pass when he is driving from one given road to another given road.
Input
There are multiple test cases.
For each test case:
The first line contains two integers N and M, representing the number of the crossings and roads.
The next M lines describe the roads. In those M lines, the i th line (i starts from 1)contains two integers X i and Y i, representing that road i connects crossing X i and Y i (X i≠Y i).
The following line contains a single integer Q, representing the number of RTQs.
Then Q lines follows, each describing a RTQ by two integers S and T(S≠T) meaning that a driver is now driving on the roads and he wants to reach roadt . It will be always at least one way from roads to roadt.
The input ends with a line of “0 0”.
Please note that: 0<N<=10000, 0<M<=100000, 0<Q<=10000, 0<X i,Y i<=N, 0<S,T<=M
Output
For each RTQ prints a line containing a single integer representing the number of crossings which the driver MUST pass.
Sample Input
5 6
1 2
1 3
2 3
3 4
4 5
3 5
2
2 3
2 4
0 0
Sample Output
0 1
分析
大概的题目意思就是给个无向图,问从a到b的路径中有几个点必须经过。
思路:根据题意,很容易就可以想到这个题就是求a到b的路径上割点的个数。然后就可以开始缩点了。把边缩成一个点,因为每条边有且仅属于一个联通块中,然后对割点和它相邻的块建边,这样就构造了一棵树。询问a边和b边,只需要找出它们分别属于哪个块中就行,所以问题转化成了一棵树中,有些点标记了是割点,现在询问两个不为割点的点路径上有多少个割点。
这样就很容易做了,以任意一个点为树根,求出每个点到树根路径上有多少个割点,然后对于询问的两个点求一次LCA就可以求出结果了,有点小细节不多说,自己画个图就清楚了。
注意:缩点后树的点数可能是2n个。
代码
#include<cstdio>
#include <vector>
#include <algorithm>
using namespace std; const int maxn = + ;
const int maxm = + ; struct Edge {
int u, to, next, vis, id;
}edge[maxm<<]; int head[maxn<<], dfn[maxn<<], low[maxn], st[maxm], iscut[maxn], subnet[maxn], bian[maxm];
int E, time, top, btot;
vector<int> belo[maxn];
void newedge(int u, int to) {
edge[E].u = u;
edge[E].to = to;
edge[E].next = head[u];
edge[E].vis = ;
head[u] = E++;
} void init(int n) {
for(int i = ;i <= n; i++) {
head[i] = -;
dfn[i] = iscut[i] = subnet[i] = ;
belo[i].clear();
}
E = time = top = btot = ;
} void dfs(int u) {
dfn[u] = low[u] = ++time;
for(int i = head[u];i != -;i = edge[i].next) {
if(edge[i].vis) continue;
edge[i].vis = edge[i^].vis = ;
int to = edge[i].to;
st[++top] = i;
if(!dfn[to]) {
dfs(to);
low[u] = min(low[u], low[to]);
if(low[to] >= dfn[u]) {
subnet[u]++;
iscut[u] = ;
btot++;
do {
int now = st[top--];
belo[edge[now].u].push_back(btot);
belo[edge[now].to].push_back(btot);
bian[edge[now].id] = btot;
to = edge[now].u;
}while(to != u);
}
}
else
low[u] = min(low[u], low[to]);
}
} int B[maxn<<], F[maxn<<], d[maxn<<][], pos[maxn<<], tot, dep[maxn<<];
bool treecut[maxn<<];
void RMQ1(int n) {
for(int i = ;i <= n; i++) d[i][] = B[i];
for(int j = ;(<<j) <= n; j++)
for(int i = ;i + j - <= n; i++)
d[i][j] = min(d[i][j-], d[i + (<<(j-))][j-]);
} int RMQ(int L, int R) {
int k = ;
while((<<(k+)) <= R-L+) k++;
return min(d[L][k], d[R-(<<k)+][k] );
} int lca(int a, int b) {
if(pos[a] > pos[b]) swap(a, b);
int ans = RMQ(pos[a], pos[b]);
return F[ans];
} // 搜树来构造RMQ LCA
void DFS(int u) {
dfn[u] = ++time;
B[++tot] = dfn[u];
F[time] = u;
pos[u] = tot;
for(int i = head[u];i != -;i = edge[i].next){
int to = edge[i].to;
if(!dfn[to]) {
if(treecut[u])
dep[to] = dep[u] + ;
else
dep[to] = dep[u];
DFS(to);
B[++tot] = dfn[u];
}
}
} void solve(int n) {
for(int i = ;i <= n; i++) {
dfn[i] = ;
}
time = tot = ;
for(int i = ;i <= n; i++) if(!dfn[i]) {
dep[i] = ;
DFS(i);
}
RMQ1(tot);
int m, u, to;
scanf("%d", &m);
while(m--) {
scanf("%d%d", &u, &to);
u = bian[u]; to = bian[to];
if(u < || to < ) {
printf("0\n"); continue;
}
int LCA = lca(u, to);
if(u == LCA)
printf("%d\n", dep[to] - dep[u] - treecut[u]);
else if(to == LCA)
printf("%d\n", dep[u] - dep[to] - treecut[to]);
else
printf("%d\n", dep[u] + dep[to] - *dep[LCA] - treecut[LCA]);
}
} int main() {
int n, m, u, to;
while(scanf("%d%d", &n, &m) != - && n){
init(n);
for(int i = ;i <= m; i++) {
scanf("%d%d", &u, &to);
edge[E].id = i;
newedge(u, to);
edge[E].id = i;
newedge(to, u);
} for(int i = ;i <= n;i ++) if(!dfn[i]) {
dfs(i);
subnet[i]--;
if(subnet[i] <= ) iscut[i] = ;
}
int ditot = btot;
for(int i = ;i <= btot; i++) treecut[i] = ;
for(int i = ;i <= btot+n; i++) head[i] = -;
E = ;
for(int i = ;i <= n; i++) if(iscut[i]) {
sort(belo[i].begin(), belo[i].end());
ditot++;
treecut[ditot] = ;
newedge(belo[i][], ditot);
newedge(ditot, belo[i][]);
for(int j = ;j < belo[i].size(); j++) if(belo[i][j] != belo[i][j-]) {
newedge(belo[i][j], ditot);
newedge(ditot, belo[i][j]);
}
}
solve(ditot);
}
return ;
}
HDU3686 Traffic Real Time Query【缩点+lca】的更多相关文章
- CH#24C 逃不掉的路 和 HDU3686 Traffic Real Time Query System
逃不掉的路 CH Round #24 - 三体杯 Round #1 题目描述 现代社会,路是必不可少的.任意两个城镇都有路相连,而且往往不止一条.但有些路连年被各种XXOO,走着很不爽.按理说条条大路 ...
- 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 ...
- HDU3686 Traffic Real Time Query
按照vdcc缩点之后一条边只会属于一个新的点集,由于这棵树上满足(不是割点) - (割点) - (不是割点)的连接方法,所以求两条边之间的必经点就是(树上距离 / 2),倍增跳lca即可 考虑到缩点后 ...
- HDU3686 Traffic Real Time Query System
P.S.此题无代码,只有口胡,因为作者码炸了. 题目大意 给你一个有 \(n\) 个点, \(m\) 条边的无向图,进行 \(q\) 次询问,每次询问两个点 \(u\) \(v\),输出两个点的之间的 ...
- UVALive-4839 HDU-3686 Traffic Real Time Query System 题解
题目大意: 有一张无向连通图,问从一条边走到另一条边必定要经过的点有几个. 思路: 先用tarjan将双连通分量都并起来,剩下的再将割点独立出来,建成一棵树,之后记录每个点到根有几个割点,再用RMQ求 ...
- 边的双联通+缩点+LCA(HDU3686)
Traffic Real Time Query System Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ...
- HDU 3686 Traffic Real Time Query System (图论)
HDU 3686 Traffic Real Time Query System 题目大意 给一个N个点M条边的无向图,然后有Q个询问X,Y,问第X边到第Y边必需要经过的点有多少个. solution ...
- 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 ...
- Traffic Real Time Query System 圆方树+LCA
题目描述 City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, ...
随机推荐
- Java实现 LeetCode 395 至少有K个重复字符的最长子串
395. 至少有K个重复字符的最长子串 找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k .输出 T 的长度. 示例 1: 输入: s = " ...
- Java实现 LeetCode 147 对链表进行插入排序
147. 对链表进行插入排序 对链表进行插入排序. 插入排序的动画演示如上.从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示). 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将 ...
- java实现Playfair 密码
一种 Playfair 密码变种加密方法如下:首先选择一个密钥单词(称为 pair)(字母不重复,且都为小写字母), 然后与字母表中其他字母一起填入至一个 5x5 的方阵中,填入方法如下: 1.首先按 ...
- java实现顺时针螺旋填入
从键盘输入一个整数(1~20) 则以该数字为矩阵的大小,把 1,2,3-n*n 的数字按照顺时针螺旋的形式填入其中.例如: 输入数字 2,则程序输出: 1 2 4 3 输入数字 3,则程序输出: 1 ...
- 一文带你了解ANR(测试人员)
一.首先,了解一下什么是ANR ANR,是"Application Not Responding"的缩写,即"应用程序无响应".系统会向用户显示一个对话框,用户 ...
- ElasticSearch系列之(一):介绍、安装(Docker、Windows、Linux)
1.介绍 Elasticsearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticsearch是用Java语言开发的,并 ...
- java关键字tranisent用法详解
作为java中的一个关键字,tranisent用的并不是很多,但是在某些关键场合,却又起着极为重要的作用,因此有必要对它进行一些必要的了解. 一.定义:声明不用序列化的成员域.(源自百度百科) 二.作 ...
- 聊一聊高并发高可用那些事 - Kafka篇
目录 为什么需要消息队列 1.异步 :一个下单流程,你需要扣积分,扣优惠卷,发短信等,有些耗时又不需要立即处理的事,可以丢到队列里异步处理. 2.削峰 :按平常的流量,服务器刚好可以正常负载.偶尔推出 ...
- 2020/06/05 JavaScript高级程序设计 函数表达式
函数表达式 函数定义的两种方式: 函数声明(函数声明提升,非标准name属性可访问给函数指定的名字) 函数声明提升:执行代码前先读取函数声明 function functionName(arg0, a ...
- linux pinmux 引脚多路复用驱动分析与使用
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/code_style/article/de ...