UOJ#465. 【HNOI2019】校园旅行 其他

原文链接www.cnblogs.com/zhouzhendong/p/UOJ465.html

前言

tmd并查集写挂,调到自闭。

cly和我写挂了同一个地方。

一下救了两个人感觉挺开心。

题解

首先直接写 bfs/记忆化dfs 可以容易地得到一个 $O(m^2)$ ,或者 $O(nm)$ 的做法。常数不大的情况下应该可以得到 70 分。

注意到本题中不要求简单路径,同一条边可以经过多次。

这意味着,我们可以在有边相连的两个同色节点之间来回走。

那么,假设两个点在同一个同色连通块,那么从其中一个点到另一个点的路径的有效信息本质只有两种:是否存在长度为奇数的路径、是否存在长度为偶数的路径。

于是,对于一个同色连通块,我们只需要保留一个带奇环的基环树即可,如果没有满足条件的基环树,就保留一个树。

然后我们考虑拆除所有连接同色点的边,留下所有连接不同色点的边。

类似的,对于剩下的边,我们只要留下一座边数尽量多的生成森林即可。

我丝薄了,写了个并查集维护。其实直接 dfs 就好了。

于是剩下 $O(n)$ 条边,只要做一做最开始的暴力就好了。

时间复杂度 $O(m\cdot \alpha(n) + n^2)$ 或 $O(m + n ^2)$ 。

代码

#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define fi first
#define se second
#define real __zzd001
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
#define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\
						For(_v2,L,R)printf("%d ",a[_v2]);puts("");
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> vi;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f|=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
const int N=5005,M=500005;
int n,m,q;
vector <int> e[N];
char s[N];
struct Edge{
	int x,y;
}E[M];
int r[N];
namespace S1{
	int fa[N],d[N];
	void init(){
		For(i,1,n)
			fa[i]=i;
		clr(d);
	}
	int getf(int x){
		if (fa[x]==x)
			return x;
		int f=getf(fa[x]);
		d[x]^=d[fa[x]];
		return fa[x]=f;
	}
}
namespace S2{
	int fa[N];
	void init(){
		For(i,1,n)
			fa[i]=i;
	}
	int getf(int x){
		return fa[x]==x?x:fa[x]=getf(fa[x]);
	}
}
int f[N][N];
int qx[N*N],qy[N*N],head=0,tail=0;
void Push(int x,int y){
	if (x>y)
		swap(x,y);
	if (!f[x][y]){
		f[x][y]=1;
		tail++;
		qx[tail]=x;
		qy[tail]=y;
	}
}
int main(){
	n=read(),m=read(),q=read();
	scanf("%s",s+1);
	For(i,1,m)
		E[i].x=read(),E[i].y=read();
	S1::init(),S2::init();
	For(i,1,m){
		int x=E[i].x,y=E[i].y;
		if (s[x]==s[y]){
			if (S1::getf(x)!=S1::getf(y)){
				e[x].pb(y),e[y].pb(x);
				S1::d[S1::getf(x)]=S1::d[x]^S1::d[y]^1;
				S1::fa[S1::fa[x]]=S1::getf(y);
			}
		}
		else {
			if (S2::getf(x)!=S2::getf(y)){
				e[x].pb(y),e[y].pb(x);
				S2::fa[S2::getf(x)]=S2::getf(y);
			}
		}
	}
	For(i,1,m){
		int x=E[i].x,y=E[i].y;
		S1::getf(x),S1::getf(y);
		if (s[x]==s[y]&&!r[S1::getf(x)]&&S1::d[x]==S1::d[y]){
			r[S1::getf(x)]=1;
			e[x].pb(y),e[y].pb(x);
		}
	}
	For(i,1,n)
		Push(i,i);
	For(i,1,m)
		if (s[E[i].x]==s[E[i].y])
			Push(E[i].x,E[i].y);
	while (head<tail){
		head++;
		int x=qx[head],y=qy[head];
		for (auto a : e[x])
			for (auto b : e[y])
				if (s[a]==s[b])
					Push(a,b);
	}
	while (q--){
		int x=read(),y=read();
		if (x>y)
			swap(x,y);
		puts(f[x][y]?"YES":"NO");
	}
	return 0;
}

  

posted @ 2019-04-11 21:38  zzd233  阅读(384)  评论(4编辑  收藏  举报