题解:P12104 [NERC2024] Managing Cluster
_Sorasaki_Hina_ · · 题解
考虑答案的上界就是树的最大匹配数,然后我们有合理的构造方式。
先说明树的最大匹配方式:dfs 一下,对于当前
然后我们考虑对颜色相同的点连颜色边,考虑匹配边和颜色边构成的一个东西。
然后会发现一个点的度数只有
然后只考虑环如何交换即可。
首先一开始长这样:
然后我们开始第一次交换:
黑色表示你还能动,红色表示你不能动了。
方框表示匹配边,黑边表示颜色边。
然后是第二次交换:
然后是第三次交换:
发现第三次交换后的局面和第一次交换后的局面一样,说明第二次、第三次交换是一个周期,我们双指针模拟一下即可。
复杂度
int T = 1 ;
const int N = 1e5 + 2 ;
int n,a[N << 1] ;
vector<int> t[N << 1] ;
vector<pair<int,int>> me,ans ;
bool vis[N << 1] ;
int cbro[N << 1],tbro[N << 1],pos[N][2] ;
inline void match (fi u,fi fa) {
for (re int v : t[u]) {
if (v == fa) continue ;
match(v,u) ;
if (!vis[v] && !vis[u]) vis[u] = vis[v] = 1,me.emplace_back(u,v) ;
}
}
inline void calc (vector<pair<int,int>> ce) {
re int k = ce.size(),l = 1,r = k - 1 ;
if (k <= 1) return ;
ans.emplace_back(ce[0].first,ce[1].first) ;
swap(ce[0].first,ce[1].first) ;
while (l < r) {
ans.emplace_back(ce[l].second,ce[r].second),swap(ce[l].second,ce[r].second) ;
++l ;
if (l == r) break ;
ans.emplace_back(ce[l].first,ce[r].first),swap(ce[l].first,ce[r].first) ;
--r ;
if (l == r) break ;
}
}
inline void solve () {
read(n) ;
for (re int i = 1 ; i <= n << 1 ; ++i) read(a[i]) ;
for (re int i = 2 ; i <= n << 1 ; ++i) {
re int u,v ;
read(u,v) ;
t[u].push_back(v),t[v].push_back(u) ;
}
match(1,0) ;
for (re int i = 1 ; i <= n << 1 ; ++i) {
if (!pos[a[i]][0]) pos[a[i]][0] = i ;
else {
pos[a[i]][1] = i ;
cbro[pos[a[i]][0]] = pos[a[i]][1] ;
cbro[pos[a[i]][1]] = pos[a[i]][0] ;
}
}
for (re auto &e : me) tbro[e.first] = e.second,tbro[e.second] = e.first ;
fill(vis + 1,vis + 1 + (n << 1),0) ;
for (re int i = 1 ; i <= (n << 1) ; ++i) {
if (!tbro[i] && !vis[i]) {
re vector<pair<int,int>> ce ;
re int u = i,v = cbro[u] ;
vis[u] = vis[v] = 1 ;
while (tbro[v]) {
u = tbro[v],vis[u] = 1 ;
ce.emplace_back(v,u) ;
v = cbro[u],vis[v] = 1 ;
}
if (ce.size()) {
ce.emplace_back(v,i) ;
calc(ce) ;
}
}
}
for (re int i = 1 ; i <= n << 1 ; ++i) {
if (!vis[i]) {
re vector<pair<int,int>> ce ;
re int u = i,v = tbro[u] ;
while (!vis[v]) {
vis[u] = vis[v] = 1 ;
ce.emplace_back(u,v) ;
u = cbro[v],v = tbro[u] ;
}
if (ce.size()) calc(ce) ;
}
}
write(ans.size(),endl) ;
for (re auto &e : ans) write(e.first,' '),write(e.second,endl) ;
ans.clear(),me.clear() ;
for (re int i = 1 ; i <= n << 1 ; ++i) t[i].clear() ;
fill(vis + 1,vis + 1 + (n << 1),0) ;
fill(cbro + 1,cbro + 1 + (n << 1),0) ;
fill(tbro + 1,tbro + 1 + (n << 1),0) ;
for (re int i = 1 ; i <= n ; ++i) pos[i][0] = pos[i][1] = 0 ;
}
int main () {
read(T) ;
while (T--) solve() ;
return 0 ;
}