HYSBZOJ 5492 [Hnoi2019]校園旅行
題目大意
分析
首先我們不難發現,一個迴文串去掉首尾之後一定是一個迴文串。
所以我們可以根據這個性質來做:
假設是一對可以通過迴文串相互到達的點對,那麼我們可以枚舉的鄰接點,的鄰接點,當同色時,它們就可以通過迴文串相互到達。然後我們按照 BFS 順序轉移即可。
這樣做我們需要枚舉所有的邊,複雜度爲的,顯然過不了這題。
代碼就不給了吧。。。
考慮如何減少邊數。
考慮將連接相同顏色的邊拿出來,這樣原圖就被劃分成若干個連通塊。
這樣的話如果某個連通塊是二分圖,那麼我們從部走到部會經過恰好奇數條邊,而從部走回部或者從部走回部會經過恰好偶數條邊。也就是說,我們恰好會得到奇數/偶數個或者。
實際上,我們對於這個連通塊,保留它的一棵生成樹就夠了。因爲題目中沒有要求只走簡單路徑,所以在原來的二分圖上走環就可以轉化成在生成樹上走重複的邊了。這樣只留下一棵生成樹的話對於答案是沒有影響的。
但當這個連通塊不是二分圖的時候,我們可以發現通過不斷地繞着環走可以改變長度奇偶性,所以我們在這個圖上的生成樹上隨便加一個自環就可以了。
對於連着不同顏色的邊也做同樣的處理,不難發現這時它一定是一個二分圖。
這樣的話邊數最多不會超過了。
我們在建好的新圖上用暴力的方法跑就可以了,複雜度爲。
注意這道題輸入數據很大,要寫個讀入優化才能過。
參考代碼
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn = 5000;
const int Maxm = 500000;
struct DSU {
int fa[Maxn + 5];
void init(int n) {
for(int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int u) {
return u == fa[u] ? u : fa[u] = find(fa[u]);
}
void unite(int u, int v) {
u = find(u), v = find(v);
if(u == v) return;
fa[u] = v;
}
bool same(int u, int v) {
return find(u) == find(v);
}
};
int N, M;
char tag[Maxn + 5];
bool f[Maxn + 5][Maxn + 5];
DSU s;
vector<int> G[Maxn + 5];
void addedge(int u, int v) {
G[u].push_back(v), G[v].push_back(u);
}
vector<int> G1[Maxn + 5];
void addedge1(int u, int v) {
if(u == v) G1[u].push_back(v);
else G1[u].push_back(v), G1[v].push_back(u);
}
queue<pair<int, int> > q;
int col[Maxn + 5];
bool has_odd;
void DFS(int u, int c) {
col[u] = c;
for(int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i];
if(tag[u] != tag[v]) continue;
if(col[u] == col[v]) has_odd = true;
if(col[v]) continue;
addedge1(u, v);
DFS(v, c ^ 1);
f[u][v] = f[v][u] = true;
q.push(make_pair(u, v));
}
}
void rebuild() {
for(int i = 1; i <= N; i++)
if(!col[i]) {
has_odd = false;
DFS(i, 2);
if(has_odd) addedge1(i, i);
}
}
void BFS() {
while(!q.empty()) {
int u = q.front().first, v = q.front().second;
q.pop();
for(int i = 0; i < (int)G1[u].size(); i++)
for(int j = 0; j < (int)G1[v].size(); j++) {
int tu = G1[u][i], tv = G1[v][j];
if(f[tu][tv]) continue;
if(tag[tu] != tag[tv]) continue;
f[tu][tv] = f[tv][tu] = true;
q.push(make_pair(tu, tv));
}
}
}
inline int read() {
char ch = getchar();
int ret = 0;
bool w = false;
while(ch > '9' || ch < '0') {
if(ch == '-') w = true;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
ret = ret * 10 + (ch ^ 48);
ch = getchar();
}
return w ? -ret : ret;
}
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
N = read(), M = read();
int Q = read();
scanf("%s", tag + 1);
s.init(N);
for(int i = 1; i <= M; i++) {
int u = read(), v = read();
addedge(u, v);
if(tag[u] != tag[v]) {
if(s.same(u, v)) continue;
addedge1(u, v);
s.unite(u, v);
}
}
rebuild();
for(int i = 1; i <= N; i++)
f[i][i] = true, q.push(make_pair(i, i));
BFS();
while(Q--) {
int u = read(), v = read();
puts(f[u][v] ? "YES" : "NO");
}
return 0;
}