题解:P15247 [WC2026] 画树
官方题解做法,可能有一点不同。
不妨设树的根都是
part1. 求解 k_{\min}
定义
注意到
记有
part2. 方案构造
首先操作是可逆的,考虑把
初始你可以在把若干对铅笔橡皮放在任意位置(铅笔和橡皮可以不用在一起),然后对
基本操作一:如果一对铅笔橡皮在同一位置,可以不影响树的形态任意同步移动。
基本操作二:定义
如果基环树就没有子树,称这次
将方案分成两步。
part 2.1 调整奇偶性
初始显然是把
然后依次把每对铅笔橡皮执行
part 2.2 调整树形态
这个部分只需要一对铅笔橡皮。
考虑
然后设
假装把
注意到
操作次数
#include<bits/stdc++.h>
using namespace std;
void setting(int k, vector<int> p);
void alter(int t, int x, int y);
void init(int c, int t) {}
struct OP {
int id,p1,p2,e1,e2;
} op[114514];
int opc;
int p[105], e[105];
vector<int> G[205], G2[205];
void alter2(int t, int x, int y) {
if(p[t]==x) return;
op[++opc]={t,p[t],x,e[t],y};
G2[p[t]].push_back(x), G2[x].push_back(p[t]);
G2[e[t]].erase(find(G2[e[t]].begin(), G2[e[t]].end(), y));
G2[y].erase(find(G2[y].begin(), G2[y].end(), e[t]));
p[t]=x, e[t]=y;
}
int deg[205], deg2[205], a[205], cnt, vis[205], path[205], dep;
int dfs(int x, int y, int d) {
vis[x]=1, path[d]=x;
if(x==y) return dep=d, 1;
for(auto i:G2[x]) if(!vis[i] && dfs(i,y,d+1)) return 1;
vis[x]=0;
return 0;
}
int combine(int id, int x, int y) {
if(x==y) return 1;
memset(vis,0,sizeof vis);
dfs(y,x,1);
int ok=0;
for(int i=1; i<=dep; i++)
for(auto j:G2[path[i]])
if(!vis[j])
ok=1;
if(!ok) return 0;
for(int i=1; i<=dep; i++) {
int z=-1;
for(auto j:G2[path[i]])
if(!vis[j])
z=j;
if(~z) {
alter2(id, z, z);
return 1;
}
alter2(id, path[i], path[i+1]);
}
}
void hide(int x) {
for(auto y:G2[x]) G2[y].erase(find(G2[y].begin(), G2[y].end(), x));
G2[x].clear();
}
int tmp[205];
void dfs2(int x, int fa) {
for(auto y:G[x]) {
if(y==fa) continue;
dfs2(y,x);
}
if(x==1) return;
int sz=0;
for(auto y:G2[x]) tmp[++sz]=y;
for(int i=2; i<=sz; i+=2) {
alter2(1, tmp[i], tmp[i]);
alter2(1, tmp[1], x);
alter2(1, tmp[i+1], tmp[i+1]);
}
if(fa!=tmp[1]) {
alter2(1, x, x);
alter2(1, fa, tmp[1]);
hide(x);
combine(1, fa, tmp[1]);
} else {
hide(x);
}
}
void paint(int n, vector<int> u, vector<int> v) {
opc=0;
for(int i=1; i<=n; i++) deg[i]=deg2[i]=0, G[i].clear(), G2[i].clear();
for(int i=0; i<n-1; i++) {
G[u[i]].push_back(v[i]), G[v[i]].push_back(u[i]);
deg[u[i]]++, deg[v[i]]++;
}
for(int i=n-1; i<2*n-2; i++) {
G2[u[i]].push_back(v[i]), G2[v[i]].push_back(u[i]);
deg2[u[i]]++, deg2[v[i]]++;
}
cnt=0;
for(int i=1; i<=n; i++)
if((deg[i]&1)!=(deg2[i]&1))
a[++cnt]=i;
if(!cnt) p[1]=e[1]=1;
for(int i=1; i<=(cnt>>1); i++) {
p[i]=a[i*2-1], e[i]=a[i*2];
if(!combine(i, p[i], e[i])) {
swap(a[i*2-1], a[i*2+1]), swap(a[i*2], a[i*2+2]);
p[i]=a[i*2-1], e[i]=a[i*2];
combine(i, p[i], e[i]);
}
}
dfs2(1,0);
// 倒着输出最终答案
int mx=0;
for(int i=1; i<=opc; i++) mx=max(mx, op[i].id);
vector<int> vec;
for(int i=1; i<=mx; i++) vec.push_back(p[i]);
setting(mx, vec);
for(int i=opc; i>=1; i--) alter(op[i].id, op[i].e1, op[i].p1);
}