【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的枚举简单应用
/** * 请用枚举方式实现如下应用: * 客户去旅店住房, * 客户分普通客户,和vip客户,vip分白金和钻石客户 * 不同的客户有不同的折扣 * 入住的房间分单人房,双人房和套房 * 不同的房间 ...
- javascript事件环微任务和宏任务队列原理
哈喽!大家好!我是木瓜太香,我又来嘞,今天来说说前端面试中经常别问到的 JS 事件环问题. JS 事件环 JS 程序的运行是离不开事件环机制的,这个机制保证在发生某些事情的时候我们有机会执行一个我们事 ...
- 转发请求RequestDispatcher()方法用于与页面的交互
jsp1代码 <form action="HelloServlet" > 账号: <input type="text" name=" ...
- 【原创】K8S使用ceph-csi持久化存储之RBD
一.集群和组件版本 K8S集群:1.17.3+Ceph集群:Nautilus(stables)Ceph-CSI:release-v3.1snapshotter-controller:release-2 ...
- Docker:三、深入Docker容器&Asp.net发版
各位看官,我们前面已经有过两篇文章的研究了,哈哈,都是皮毛... 今天我们来看看docker容器内部,一探究竟... 一.进入docker容器 进入Linux容器非常简单,直接使用如下命令即可: do ...
- 龙芯3A4000-Debian 10上常用软件记录
所用平台 硬件:龙芯3a4000 (MIPS64el) 操作系统:Debian 10(buster)+ MATE桌面 内核版本:4.19.90 以下所有软件同样适用于x86体系结构的Linux发行版. ...
- 关于excel表格中只复制筛选后的数据
今天笔者在整个一个表格中的数据,需要将原表格的数据根据一些条件筛选后,整理到新的excel表中 但是发现每次操作,都将筛选条件之外的数据也粘贴进去了,但笔者确实又只选中了部分数据 经过多种方式尝试后, ...
- 论文阅读笔记: Natural Language Inference over Interaction Space
这篇文章提出了DIIN(DENSELY INTERACTIVE INFERENCE NETWORK)模型. 是解决NLI(NATURAL LANGUAGE INFERENCE)问题的很好的一种方法. ...
- kafka面试总结
本文为复习期间面试总结 从以下方面对kafka面试进行总结:基本原理架构/项目实践/生产者/消费者/协调者/存储层/控制器 基本原理架构 简单讲下什么是kafka[一句话概括/架构图] 消息队列选型 ...
- Python-全局函数(内置方法、内置函数)
Python有很多内置方法,这些都全局可用 abs() 求数值的绝对值,如果是复数则返回其模 print(abs(-17), abs(30.2), abs(3+4j)) # Python中复数表示为 ...