[GYM102900K]Traveling Merchant

IV.[GYM102900K]Traveling Merchant

首先,观察到路径一定是一个 \(\rho\) 形的东西,其中在 \(\rho\) 的交点之前,一直都是黑白点交替,到了交点处是两个同色点。

于是我们就只保留异色边建一张图,则问题就转变为给你多对同色点,询问有无从 \(1\) 经过其中一个点到达另一个点的简单路径。

考虑建出异色边图的圆方树。则我们只需以 \(1\) 为根遍历圆方树,将询问的两个圆点升到它们的父亲——两个方点,然后判断它们是否成祖孙关系即可。

时间复杂度 \(O(n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
int T,n,m,c;
char s[200100];
namespace Tree{
	vector<int>v[400100];
	void ae(int x,int y){v[x].push_back(y),v[y].push_back(x);}
	int dfn[400100],sz[400100],tot,fa[400100];
	void dfs(int x,int P){
		fa[x]=P,dfn[x]=++tot,sz[x]=1;
		for(auto y:v[x])if(y!=P)dfs(y,x),sz[x]+=sz[y];
	}
}
namespace Graph{
	vector<int>v[200100];
	int dfn[200100],low[200100],tot;
	stack<int>s;
	void Tarjan(int x){
		dfn[x]=low[x]=++tot,s.push(x);
		for(auto y:v[x]){
            if(!dfn[y]){
				Tarjan(y),low[x]=min(low[x],low[y]);
				if(low[y]>=dfn[x]){
					c++;
					while(s.top()!=y)Tree::ae(c,s.top()),s.pop();
                    Tree::ae(c,s.top()),s.pop();
                    Tree::ae(c,x);
                }
            }else low[x]=min(low[x],dfn[y]);
        }
	}
}
vector<pair<int,int> >q;
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%s",&n,&m,s+1),c=n;
		for(int i=1,x,y;i<=m;i++){
			scanf("%d%d",&x,&y),x++,y++;
			if(s[x]!=s[y])Graph::v[x].push_back(y),Graph::v[y].push_back(x);
			else q.push_back(make_pair(x,y));
		}
		Graph::Tarjan(1),Tree::dfs(1,0);
		bool ok=false;
		for(auto i:q){
			if(!Graph::dfn[i.first]||!Graph::dfn[i.second])continue;
			int x=i.first,y=i.second;
			if(Tree::fa[x])x=Tree::fa[x];
			if(Tree::fa[y])y=Tree::fa[y];
			if(Tree::dfn[x]>Tree::dfn[y])swap(x,y);
			if(Tree::dfn[x]+Tree::sz[x]-1>=Tree::dfn[y]){ok=true;break;}
		}
		puts(ok?"yes":"no");
		for(int i=1;i<=n;i++)Graph::dfn[i]=Graph::low[i]=0,Graph::v[i].clear();Graph::tot=0;
		for(int i=1;i<=c;i++)Tree::dfn[i]=Tree::sz[i]=Tree::fa[i]=0,Tree::v[i].clear();c=0;
		while(!Graph::s.empty())Graph::s.pop();
		q.clear();
	}
	return 0;
}

posted @ 2021-04-06 13:45  Troverld  阅读(68)  评论(0编辑  收藏  举报