【Targan+LCA】HDU 3686 Traffic Real Time Query
题目内容
洛谷链接
给出一个\(n\)个节点,\(m\)条边的无向图和两个节点\(s\)和\(t\),问这两个节点的路径中有几个点必须经过。
输入格式
第一行是\(n\)和\(m\)。
接下来\(m\)行,给出两个数表示这两个节点之间存在一条边。
接下来一行一个整数\(Q\),表示询问个数。
接下来\(Q\)行,每行两个整数\(s\)和\(t\)(\(s\not= t\))。
数据范围
\(0<n\le 10000,0<m\le 100000,0<Q\le 10000,0<s,t\le m\)
输出格式
对于每个询问,输出一行表示答案
样例输入
5 6
1 2
1 3
2 3
3 4
4 5
3 5
2
2 3
2 4
0 0
样例输出
0
1
思路
这个题问的就是\(s\)到\(t\)路径上割点的个数。
点双缩点,可以知道,每条边仅在一个联通块中,把割点和它相邻的联通块建边,从而构造棵树。
询问\(s\)边和\(t\)边,需要求它们分别属于哪个连通块。所以问题转化成了一棵树中,有些点已标记为割点,询问两个非割点之间路径上有多少个割点。
因此选择一个点作为树根,求出每个点到树根路径上有多少个割点,然后对于询问的两个点求一次LCA即可。
代码
#include<cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=10000+10;
const int maxm=100000+10;
struct Edge{
int u,to,next,vis,id;
}edge[maxm<<1];
int head[maxn<<1],dfn[maxn<<1],low[maxn],st[maxm],iscut[maxn],subnet[maxn],bian[maxm];
int cnt,time,top,btot;
vector<int> belong[maxn];
void add(int u,int to){
edge[cnt].u=u;
edge[cnt].to=to;
edge[cnt].next=head[u];
edge[cnt].vis=0;
head[u]=cnt++;
}
void init(int n){
for(int i=0;i<=n;i++){
head[i]=-1;
dfn[i]=iscut[i]=subnet[i]=0;
belong[i].clear();
}
cnt=time=top=btot=0;
}
void dfs(int u){
dfn[u]=low[u]=++time;
for(int i=head[u];i!=-1;i=edge[i].next){
if(edge[i].vis)continue;
edge[i].vis=edge[i^1].vis=1;
int to=edge[i].to;
st[++top]=i;
if(!dfn[to]){
dfs(to);
low[u]=min(low[u],low[to]);
if(dfn[u]<=low[to]){
subnet[u]++;
iscut[u]=1;
btot++;
do{
int now=st[top--];
belong[edge[now].u].push_back(btot);
belong[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<<2],F[maxn<<2],d[maxn<<2][20],pos[maxn<<2],tot,dep[maxn<<1];
bool treecut[maxn<<1];
void RMQ1(int n){
for(int i=1;i<=n;i++)d[i][0]=B[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+j-1<=n;i++)
d[i][j]=min(d[i][j-1],d[i + (1<<(j-1))][j-1]);
}
int RMQ(int L,int R){
int k=0;
while((1<<(k+1))<=R-L+1) k++;
return min(d[L][k],d[R-(1<<k)+1][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!=-1;i=edge[i].next){
int to=edge[i].to;
if(!dfn[to]){
if(treecut[u])
dep[to]=dep[u] + 1;
else
dep[to]=dep[u];
DFS(to);
B[++tot]=dfn[u];
}
}
}
void solve(int n){
for(int i=0;i<=n;i++) {
dfn[i]=0;
}
time=tot=0;
for(int i=1;i<=n;i++)
if(!dfn[i]){
dep[i]=0;
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<0||to<0){
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]-2*dep[LCA]-treecut[LCA]);
}
}
int main(){
int n,m,u,to;
while(scanf("%d%d",&n,&m)!=-1 && n){
init(n);
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&to);
edge[cnt].id=i;
add(u,to);
edge[cnt].id=i;
add(to,u);
}
for(int i=1;i<=n;i++)
if(!dfn[i]){
dfs(i);
subnet[i]--;
if(subnet[i]<=0)iscut[i]=0;
}
int ditot=btot;
for(int i=1;i<=btot;i++)
treecut[i]=0;
for(int i=1;i<=btot+n;i++)
head[i]=-1;
cnt=0;
for(int i=1;i<=n;i++)
if(iscut[i]){
sort(belong[i].begin(),belong[i].end());
ditot++;
treecut[ditot]=1;
add(belong[i][0],ditot);
add(ditot,belong[i][0]);
for(int j=1;j<belong[i].size();j++)
if(belong[i][j]!=belong[i][j-1]){
add(belong[i][j],ditot);
add(ditot,belong[i][j]);
}
}
solve(ditot);
}
return 0;
}
【Targan+LCA】HDU 3686 Traffic Real Time Query的更多相关文章
- 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。这题有重边!!!
http://acm.hdu.edu.cn/showproblem.php?pid=3686 我要把这题记录下来. 一直wa. 自己生成数据都是AC的.现在还是wa.留坑. 我感觉我现在倒下去床上就能 ...
- 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(点双连通)
题意 给定一张 \(n\) 个点 \(m\) 条边的无向图,\(q\) 次询问,每次询问两边之间的必经之点个数. 思路 求两点之间必经之边的个数用的是边双缩点,再求树上距离.而对比边双和点双之 ...
- 【刷题】HDU 5869 Different GCD Subarray Query
Problem Description This is a simple problem. The teacher gives Bob a list of problems about GCD (Gr ...
- 【线段树】HDU 5493 Queue (2015 ACM/ICPC Asia Regional Hefei Online)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5493 题目大意: N个人,每个人有一个唯一的高度h,还有一个排名r,表示它前面或后面比它高的人的个数 ...
- 【归并排序】【逆序数】HDU 5775 Bubble Sort
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5775 题目大意: 冒泡排序的规则如下,一开始给定1~n的一个排列,求每个数字在排序过程中出现的最远端 ...
- 【线段树】HDU 5443 The Water Problem
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5443 题目大意: T组数据.n个值,m个询问,求区间l到r里的最大值.(n,m<=1000) ...
- 【刷题】HDU 2222 Keywords Search
Problem Description In the modern time, Search engine came into the life of everybody like Google, B ...
随机推荐
- java实现内网通信
package newTest; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; ...
- MongoDB基础总结
1.数据可基本操作 1. 创建数据库 use databaseName 选择一个数据库,如果数据库不存在就自动创建一个数据库 只有向数据库中插入数据时,数据库才会被真实创建出来,而当数据库中没有数据 ...
- java 二维码生成(可带图片)springboot版
本文(2019年6月29日 飞快的蜗牛博客) 有时候,男人和女人是两个完全不同的世界,男人的玩笑和女人的玩笑也完全是两码事,爱的人完全不了解你,你也不要指望一个女人了解你,所以男的不是要求别人怎么样, ...
- Web开发初探(系统理解Web知识点)
一.Web开发介绍 我们看到的网页通过代码来实现的 ,这些代码由浏览器解释并渲染成你看到的丰富多彩的页面效果. 这个浏览器就相当于Python的解释器,专门负责解释和执行(渲染)网页代码. 写网页的代 ...
- 不光是查找值!"二分搜索"
从有序数组中查找某个值 问题描述:给定长度为n的单调不下降数列a0,…,an-1和一个数k,求满足ai≥k条件的最小的i.不存在则输出n. 限制条件:1≤n≤1060≤a0≤a1≤…≤an-1< ...
- oracle之三资源管理
Oracle 资源管理 12.1 为什么要使用Oracle资源管理器 传统意义上,系统的资源分配是由OS来完成的,但是对于数据库资源,OS分配资源会带来一些问题: 以Linux为例,最为突出的一个问题 ...
- web网站——apache和nginx对比02
nginx介绍 Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为“engine X”,是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP 代理 ...
- profile对比std::regex与boost::regex的性能
c++11标准库的regex比boost库的regex之间的性能差距接近5倍,这是为什么?stackflow上也找到一篇post<c++11 regex slower than python&g ...
- 刷题[MRCTF2020]Ezpop
解题思路 打开一看直接是代码审计的题,就嗯审.最近可能都在搞反序列化,先把反序列化的题刷烂,理解理解 代码审计 Welcome to index.php <?php //flag is in f ...
- PHP_Code_Challenge 1~30
1. 1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY= <?php error_reporting(0); require __DIR__ ...