题目

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】的更多相关文章

  1. CH#24C 逃不掉的路 和 HDU3686 Traffic Real Time Query System

    逃不掉的路 CH Round #24 - 三体杯 Round #1 题目描述 现代社会,路是必不可少的.任意两个城镇都有路相连,而且往往不止一条.但有些路连年被各种XXOO,走着很不爽.按理说条条大路 ...

  2. 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 ...

  3. HDU3686 Traffic Real Time Query

    按照vdcc缩点之后一条边只会属于一个新的点集,由于这棵树上满足(不是割点) - (割点) - (不是割点)的连接方法,所以求两条边之间的必经点就是(树上距离 / 2),倍增跳lca即可 考虑到缩点后 ...

  4. HDU3686 Traffic Real Time Query System

    P.S.此题无代码,只有口胡,因为作者码炸了. 题目大意 给你一个有 \(n\) 个点, \(m\) 条边的无向图,进行 \(q\) 次询问,每次询问两个点 \(u\) \(v\),输出两个点的之间的 ...

  5. UVALive-4839 HDU-3686 Traffic Real Time Query System 题解

    题目大意: 有一张无向连通图,问从一条边走到另一条边必定要经过的点有几个. 思路: 先用tarjan将双连通分量都并起来,剩下的再将割点独立出来,建成一棵树,之后记录每个点到根有几个割点,再用RMQ求 ...

  6. 边的双联通+缩点+LCA(HDU3686)

    Traffic Real Time Query System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  7. HDU 3686 Traffic Real Time Query System (图论)

    HDU 3686 Traffic Real Time Query System 题目大意 给一个N个点M条边的无向图,然后有Q个询问X,Y,问第X边到第Y边必需要经过的点有多少个. solution ...

  8. 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 ...

  9. Traffic Real Time Query System 圆方树+LCA

    题目描述 City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, ...

随机推荐

  1. Shell脚本 (三) 条件判断 与 流程控制

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 六.条件判断 1.基本语法 [ condition ](注意condition 前后要有空格) 注意:条 ...

  2. (Java实现) 洛谷 P1781 宇宙总统

    题目背景 宇宙总统竞选 题目描述 地球历公元6036年,全宇宙准备竞选一个最贤能的人当总统,共有n个非凡拔尖的人竞选总统,现在票数已经统计完毕,请你算出谁能够当上总统. 输入输出格式 输入格式: pr ...

  3. Java实现 蓝桥杯 算法提高 递推求值

    算法提高 递推求值 时间限制:1.0s 内存限制:256.0MB 问题描述 已知递推公式: F(n, 1)=F(n-1, 2) + 2F(n-3, 1) + 5, F(n, 2)=F(n-1, 1) ...

  4. Java实现 蓝桥杯VIP 算法提高 3-2求存款

    算法提高 3-2求存款 时间限制:1.0s 内存限制:256.0MB 问题描述 见计算机程序设计基础(乔林)P50第5题. 接受两个数,一个是用户一年期定期存款金额,一个是按照百分比格式表示的利率,计 ...

  5. Java实现 蓝桥杯 算法提高 快速排序

    试题 算法提高 快速排序 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 用递归来实现快速排序(quick sort)算法.快速排序算法的基本思路是:假设要对一个数组a进行排序,且a ...

  6. PAT 在霍格沃茨找零钱

    如果你是哈利·波特迷,你会知道魔法世界有它自己的货币系统 —— 就如海格告诉哈利的:“十七个银西可(Sickle)兑一个加隆(Galleon),二十九个纳特(Knut)兑一个西可,很容易.”现在,给定 ...

  7. 09_EM算法

    今天是2020年3月5日星期四.预计开学时间不会早于四月初,真是好消息,可以有大把的时间整理知识点(实际上发文章的时间都6月6号了,希望9月份能开学啊,不耽误找工作~).每次导师找,整个人会变的特别烦 ...

  8. iOS — 内存分配与分区

    1  RAM ROM RAM:运行内存,不能掉电存储.ROM:存储性内存,可以掉电存储,例如内存卡.Flash.      由于RAM类型不具备掉电存储能力(即一掉电数据消失),所以app程序一般存放 ...

  9. void out2() const{

    include "stdafx.h" include using namespace std; class aa{ int num; public: aa(){ int b =10 ...

  10. centos7上安装memcached以及PHP安装memcached扩展(二)

    开始在 PHP 中使用 Memcached 前, 我们需要确保已经安装了 Memcached  服务,接下来安装 php-memcached 扩展. PHP Memcached 扩展安装 第一步:如果 ...