SS241006B. 結論題
題意
給你一個無向圖,每個點有點權 \(1 \le a_i \le 10^6\) 和顏色 \(c_i=0/1\)。可以進行若干次操作:選擇任意一條邊,交換兩個點的點權,如果兩個點的顏色相同,兩個點的顏色分別取反。給出初始狀態和一個終態,判斷是否存在到達終態的方案。
思路
真結論題。
這個操作非常噁心。巧妙地轉化一下可以變成每次選定一條邊,交換點權和顏色,然後對顏色取反。然後我們發現這個操作是可逆的。
考慮二分圖怎麼做。
首先原圖可以分成若干個連通塊分別做。
對於一個連通塊,因為它是連通的,類似氣泡排序,所以點權是可以任意排序的,但是顏色還有取反操作。
對於二分圖,一個左部的點如果換到了左部,顏色不變,換到了右部,顏色取反。
所以對於每個點,我們記錄一個二元組 \((點權,點在左部時的顏色)\),對初態和終態都做這樣的記錄。如果初態和終態的元素相同,就一定有可行方案。對於初態的某個二元組和終態的某個二元組的一對匹配,如果在終態的原圖,這個二元組在右部,那麼初態的那個二元組也移到右部對應位置就行,這是可以一一匹配的。因為這是一個連通塊,所以可以任意排序,因此結論成立。
對於非二分圖的情況。結論是,初態點權和終態點權集合相同,且初態原圖顏色 \(0\) 和終態原圖顏色 \(0\) 的個數奇偶性相同(\(1\) 也一樣)。必要性顯然。下面證明其充分性。
首先我們在原圖隨便找一個生成二分圖,比如找一個生成樹。然後對每個點維護上面提到的二元組 \((點權,點在左部時的顏色)\)。由上面的結論可以知道,如果初態的二元組集合和終態相同,就一定有可行的方案。也就是說,在這個二分圖上面我們可以任意排序這些二元組同時不改變它們的值。
原圖就是二分圖上加上了若干條邊,如果在不同部加邊(生成樹奇數層和偶數層連邊),圖還是一個二分圖,沒有新的性質。如果在生成樹奇數和奇數(或偶數和偶數)層連邊,就出現了奇環。
類似氣泡排序,在這個奇環上所有點的點權可以任意排序,其實不需要再奇環上面排序,如果在二分圖的路徑上,不僅也可以任意排序,而且二元組的 \(點在左部的顏色\) 這個值還不會改變。現在證明之前那個結論的充分性。我們可以透過二分圖上的路徑把兩個顏色相同的點放到非二分圖的那條邊的兩個端點,然後交換它們,並取反顏色,這樣某個顏色的總數就會 \(-2\) 了。而且我們只需要一個奇環,因為你可以把整棵生成樹的點任意排序,把你想要改變顏色的點顏色取反。因此利用某一個奇環做若干次顏色取反,就可以使初態和終態二元組的集合相同了,然後由於二分圖可以任意排序二元組,所以結論充分。
證畢。
code
#include<bits/stdc++.h>
//#define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
const int N=1e5+7;
template <typename T>
inline void read(T &x) {
x=0;
T fl=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') fl=-1;
for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
x=x*fl;
}
template <typename T>
inline void write(T x,char ch) {
static int st[10];
int top=0;
if(x<0) putchar('-'),x=-x;
do {
st[top++]=x%10;
x/=10;
}while(x);
while(top) putchar(st[--top]+'0');
putchar(ch);
}
int T,n,m;
vector<int> to[N];
int vi[N];
int u,v;
char ch[N];
typedef pair<int,int> pii;
#define fi first
#define se second
pii s[N],t[N];
bool checkeft(int &cs,int &ct,vector<pii> &vecs,vector<pii> &vect,int u) {
bool ans=1;
if(s[u].se) cs++;
if(t[u].se) ct++;
if(vi[u]==2) s[u].se^=1,t[u].se^=1;
vecs.push_back(s[u]);vect.push_back(t[u]);
for(int v:to[u]) {
if(!vi[v]) vi[v]=(vi[u]==1?2:1),ans&=checkeft(cs,ct,vecs,vect,v);
else if(vi[u]==vi[v]) ans=0;
}
return ans;
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#else
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
#endif
read(T);
while(T--) {
read(n),read(m);
rep(i,1,m) {
read(u),read(v);
to[u].push_back(v),to[v].push_back(u);
}
rep(i,1,n) read(s[i].fi);
sf("%s",ch+1);
rep(i,1,n) s[i].se=(ch[i]=='R'?1:0);
rep(i,1,n) read(t[i].fi);
sf("%s",ch+1);
rep(i,1,n) t[i].se=(ch[i]=='R'?1:0);
bool ans=1;
rep(k,1,n) {
if(!ans) break;
if(vi[k]) continue;
vector<pii> vecs,vect;
int cnts=0,cntt=0;
vi[k]=1;
bool check=checkeft(cnts,cntt,vecs,vect,k);
sort(vecs.begin(),vecs.end());
sort(vect.begin(),vect.end());
if(check) {
rep(i,0,(int)vecs.size()-1) {
if(vecs[i]!=vect[i]) {
ans=0;
break;
}
}
}else{
if((cnts&1)!=(cntt&1)) ans=0;
rep(i,0,(int)vecs.size()-1) {
if(vecs[i].fi!=vect[i].fi) {
ans=0;
break;
}
}
}
}
if(ans) pf("YES\n");
else pf("NO\n");
rep(i,1,n) to[i].clear(),vi[i]=0;
}
}