Loading

HDU 3686 Traffic Real Time Query System (图论)

HDU 3686 Traffic Real Time Query System

题目大意

给一个N个点M条边的无向图,然后有Q个询问X,Y,问第X边到第Y边必需要经过的点有多少个。

solution

显然园方树+tarjan求LCA,然后求两条边之间的点
必经的点的数量就是圆点的数量,然后进行分类讨论

  • \(LCA\)为圆点:
    那么其中一个点到\(LCA\)的圆点数量为\((deep[x] - deep[lca])/2\),因为\(LCA\)为圆点被算了两遍,所以要-1
  • \(LCA\)为方点:
    那么其中一个点到\(LCA\)的圆点数量为\((deep[x] - deep[lca]- 1)/2\),那么两个点之间的圆点数量就是\((deep[x] + deep[y] - 2 * deep[lca])- 1\)

由此可见,两种情况算下来,答案的式子是一样的,所以直接上板子算答案就行了,这道题的代码还是比较考验码力的……

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

#define v e[i].to
const int maxn=10000+3,maxe=100000+3;
int n,m,tot,head[maxn],h[2*maxn],js,dfs_clock,deep[2*maxn],father[2*maxn];
int bcc_cnt,sta[maxn],top,dfn[maxn],low[maxn];
bool vis[2*maxn];

struct edge{
	int from,to,next;
}e[2*maxe],ed[2*maxe];

inline void Add(int a,int b){//原图
	e[++tot].from=a;
	e[tot].to=b;
	e[tot].next=head[a];
	head[a]=tot;
}

inline void Add2(int a,int b){//圆方树
	ed[++js].from=a;
	ed[js].to=b;
	ed[js].next=h[a];
	h[a]=js;
}

inline void tarjan(int u){
	low[u]=dfn[u]=++dfs_clock;
	sta[++top]=u;
	for(int i=head[u];i;i=e[i].next){
		if(dfn[v]) low[u]=min(low[u],dfn[v]);
		else{
			tarjan(v);
			low[u]=min(low[v],low[u]);
			if(low[v]==dfn[u]){
				++bcc_cnt;
				int temp;
				do{
					temp=sta[top];
					top--;
					Add2(n+bcc_cnt,temp);
					Add2(temp,n+bcc_cnt);
				}while(temp!=v);
				Add2(u,n+bcc_cnt);
				Add2(n+bcc_cnt,u);
			}
		}
	}
}

inline void init(){
	tot=0; js=0; top=0; dfs_clock=0; bcc_cnt=0;
	memset(head,0,sizeof(head));
	memset(e,0,sizeof(e));
	memset(h,0,sizeof(h));
	memset(ed,0,sizeof(ed));
	memset(sta,0,sizeof(sta));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(deep,0,sizeof(deep));
	memset(vis,0,sizeof(vis));
	memset(father,0,sizeof(father));
	memset(sta,0,sizeof(sta));
}

inline void dfs(int x){
	vis[x]=1;
	for(int i=h[x];i;i=ed[i].next){
		int now=ed[i].to;
		if(vis[now]) continue;
		deep[now]=deep[x]+1;
		father[now]=x;
		dfs(now);
	}
}

inline int find(int a,int b){//非倍增也可
	if(deep[a]<deep[b]) swap(a,b);
	while(deep[a]>deep[b]) a=father[a];
	while(a!=b){
		a=father[a];
		b=father[b];
	}
	return a;
}

inline int len(int a,int b){
	int lca=find(a,b);
	return (deep[a]+deep[b]-2*deep[lca])/2-1;
}

int main(){
	while(1){
		scanf("%d%d",&n,&m);
		if(n==0&&m==0) return 0;
		init();
		for(int i=1;i<=m;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			Add(x,y);
			Add(y,x);
		}
		for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
		for(int i=1;i<=n+bcc_cnt;i++) if(!vis[i]) dfs(i);
		int t;
		scanf("%d",&t);
		while(t--){
			int x,y;
			scanf("%d%d",&x,&y);
			int a=e[x*2].from,b=e[x*2].to,c=e[y*2].from,d=e[y*2].to; //枚举节点
			printf("%d\n",max(max(len(b,d),len(a,d)),max(len(b,c),len(a,c))));
		}
	}
}

提交语言GCC、GCC、GCC!!!
md重要的事情说三遍,淦……

posted @ 2020-05-07 16:25  Gary_818  阅读(121)  评论(0编辑  收藏  举报