AT_abc318_g 题解

因为是图上路径是否经过某个点的问题,所以考虑建出圆方树,然后根据圆方树的性质,\(a\)\(c\) 存在经过 \(b\) 的路径等价于 \(a,c\) 在圆方树上的路径经过 \(b\) 或者 \(b\) 所连接的方点,考虑暴力在圆方树上跳 LCA 即可,时间复杂度 \(O(n + m)\)

#include<bits/stdc++.h> 

using namespace std;

const int maxn = 4e5+114;

int n,m,cnt;
std::vector<int> G[maxn],T[maxn<<1];
int fa[maxn];

int dfn[maxn], low[maxn], dfc;
int stk[maxn],tp;
int f[maxn];
int dep[maxn<<1];
int val[maxn<<1];
int a,b,c;
void Tarjan(int u) {
  low[u] = dfn[u] = ++dfc;            
  stk[++tp] = u;                 
  for (int v : G[u]){               
    if (!dfn[v]) {                    
      Tarjan(v);                          
      low[u] = std::min(low[u], low[v]);  
      if (low[v] == dfn[u]) { 
        ++cnt;   
        for (int x = 0; x != v; --tp) {
          x = stk[tp];
          T[cnt].push_back(x);
          T[x].push_back(cnt);
          val[cnt]|=val[x];
        }
        val[cnt]|=val[u];
        T[cnt].push_back(u);
        T[u].push_back(cnt);
      }
    }else
      low[u] = std::min(low[u], dfn[v]);
  }
}
void build(){
	cnt=n;
	for(int u=1;u<=n;u++){
		if(!dfn[u]) Tarjan(u), --tp;
	}
	for(int i=n+1;i<=cnt;i++){
		for(int u:T[i]){
			f[u]=i;
		}	
	} 
}
void dfs(int u,int father){
	fa[u]=father;
	dep[u]=dep[father]+1;
	for(int v:T[u]){
		if(v==father) continue;
		dfs(v,u);
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	int a,b,c;
	cin>>a>>b>>c;
	val[b]=1;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	build();
	dfs(1,0);
	int ans=0;
	ans|=(val[a]|val[c]);
	while(a!=c){
		if(dep[a]<dep[c]) swap(a,c);
		a=fa[a];
		ans|=(val[a]|val[c]);
	} 
	cout<<(ans==1?"Yes\n":"No\n");
	return 0;
}

其实这题还可以多组询问,考虑把询问挂在 \(b\) 上然后树剖即可。时间复杂度是 \(O(q \log n + n \log n + m)\) 的。

posted @ 2024-01-30 23:57  ChiFAN鸭  阅读(9)  评论(0编辑  收藏  举报