【PNR#2 Div1 C】图同构(图论)

图同构

题目链接:PNR#2 Div1 C

题目大意

给你两个边集一样的图,点有黑白两色,而且有点权。
你操作若干次,每次选择一条边,把连着的两个点点权交换,若两点同色则同时反色。
然后问你 A 图能否通过操作得到 B 图。

思路

发现部分分有个二分图,思考一下。

发现这个颜色的操作很迷,考虑放到二分图上。
发现如果你把其中的一边的点都反色一下,那操作就变成了交换两边的颜色。
那就跟交换边权统一了。

那我们就可以对于每个连通块,查询它们有的点权+颜色集合是否一样即可。

接着问题是不是二分图,考虑会有什么影响。
而且首先一定会有的是奇环。
然后考虑操作这条边会怎样。
那你可以内部选一样的颜色消去,那也就是说,你两个图,需要的颜色的差是偶数倍的话,你就可以把它转成不相差。
然后也就没啥了,那如果可以的话你就不用判断颜色了。

代码

#include<cstdio>
#include<vector>
#include<algorithm>

using namespace std;

const int N = 1e6 + 100;
struct node {
	int to, nxt;
}e[N << 1];
int T, n, m, le[N], KK, col[N], tot;
int a[N], b[N], G1, G2;
vector <int> A[2], B[2];
char s[N], t[N];
bool Op[N], ji;

void clr() {
	for (int i = 1; i <= n; i++) le[i] = 0; KK = 0;
	for (int i = 1; i <= n; i++) col[i] = 0; tot = 0;
}

void add(int x, int y) {
	e[++KK] = (node){y, le[x]}; le[x] = KK;
}

void dfs(int now, int op) {
	if (col[now]) {
		if (Op[now] != op) ji = 1;
		return ;
	}
	col[now] = tot; Op[now] = op;
	A[(s[now] == 'R') ^ op].push_back(a[now]);
	B[(t[now] == 'R') ^ op].push_back(b[now]);
	if (s[now] == 'R') G1++; if (t[now] == 'R') G2++;
	for (int i = le[now]; i; i = e[i].nxt)
		dfs(e[i].to, op ^ 1);
}

bool same(vector <int> a, vector <int> b) {
	sort(a.begin(), a.end()); sort(b.begin(), b.end());
	return a == b;
}

int main() {
	scanf("%d", &T);
	while (T--) {
		scanf("%d %d", &n, &m);
		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++) scanf("%d", &a[i]);
		scanf("%s", s + 1);
		for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
		scanf("%s", t + 1);
		
		bool yes = 1;
		for (int i = 1; i <= n; i++)
			if (!col[i]) {
				A[0].clear(); A[1].clear(); B[0].clear(); B[1].clear();
				G1 = G2 = 0; ji = 0;
				tot++; dfs(i, 0);
				if (ji) {
					for (int j = 0; j < A[1].size(); j++) A[0].push_back(A[1][j]);
					for (int j = 0; j < B[1].size(); j++) B[0].push_back(B[1][j]);
					if ((G1 - G2) % 2 != 0 || !same(A[0], B[0])) {
						yes = 0; break;
					}
				}
				else {
					if ((G1 - G2) % 2 != 0 || !same(A[0], B[0]) || !same(A[1], B[1])) {
						yes = 0; break;
					}
				}
			}
		
		clr();
		if (yes) printf("YES\n");
			else printf("NO\n");
	}
	
	return 0;
}
posted @ 2022-10-27 21:24  あおいSakura  阅读(68)  评论(0)    收藏  举报