2019.04.02【洛谷P4320】道路相遇(圆方树)

传送门


解析:

换根支配树?不要想了,你要是明白支配怎么建的你就知道这玩意不存在换根的

显然在无向图上除了起点终点以外的必经点就是割点。

显然我们就是询问路径上割点个数。

建立广义圆方树,显然路径上的所有圆点就是割点。

相当于询问圆方树路径上圆点个数。

这个嘛。。。怎么开心怎么玩是吧。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

using std::cout;
using std::cerr;

cs int N=5e5+5;;
int n,m,q;

int ext;
namespace Tree{
	static cs int N=::N<<1;
	std::vector<int> G[N];
	inline void addedge(int u,int v){
		G[u].push_back(v);
		G[v].push_back(u);
	}
	
	int fa[N],dep[N],top[N],siz[N],son[N];
	
	void dfs1(int u){
		siz[u]=1;
		for(int &v:G[u])if(v!=fa[u]){
			fa[v]=u;
			dep[v]=dep[u]+1;
			dfs1(v);
			siz[u]+=siz[v];
			if(siz[v]>siz[son[u]])son[u]=v;
		}
	}
	
	void dfs2(int u){
		if(son[u]){
			top[son[u]]=top[u];
			dfs2(son[u]);
		}
		else return ;
		for(int &v:G[u])if(v!=fa[u]&&v!=son[u]){
			top[v]=v;
			dfs2(v);
		}
	}
	
	inline int LCA(int u,int v){
		while(top[u]!=top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
		return dep[u]>dep[v]?v:u;
	}
	
	inline void build(){dfs1(1),top[1]=1,dfs2(1);}
	
	inline int query(int u,int v){
		int p=LCA(u,v);
		return (dep[u]+dep[v]-dep[p]*2)/2+1; 
	}
}

namespace Graph{
	static cs int N=::N;
	std::vector<int> G[N];
	inline void addedge(int u,int v){
		G[u].push_back(v);
		G[v].push_back(u);
	}
	
	int dfn[N],low[N],dfs_clock;
	int sta[N],top;
	void tarjan(int u){
		dfn[u]=low[u]=++dfs_clock;
		sta[++top]=u;
		for(int &v:G[u]){
			if(!dfn[v]){
				tarjan(v);
				low[u]=std::min(low[u],low[v]);
				if(low[v]>=dfn[u]){
					Tree::addedge(++ext,u);
					int x;
					do{
						x=sta[top--];
						Tree::addedge(x,ext);
					}while(x!=v);
				}
			}
			else low[u]=std::min(low[u],dfn[v]);
		}
	} 
}

signed main(){
	ext=n=getint(),m=getint();
	for(int re i=1;i<=m;++i)Graph::addedge(getint(),getint());
	Graph::tarjan(1);
	Tree::build();
	q=getint();
	while(q--)cout<<Tree::query(getint(),getint())<<"\n";
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值