To irrigate the wilderness that's still asleep

【AGC025E】Walking on a Tree。

怎么还有第二关。

设一条边被经过的次数为 \(d_i\)。则答案的最大值显然是 \(\sum min(d_i,2)\)。尝试通过构造达到这个最大值。

不妨考虑一点更加严格的限制:我们希望这条边正着经过和反着经过的次数差 \(\le 1\)。而我们很快就 \(recall\) 欧拉回路:如果图有欧拉回路,则对于割 \((A,B)\),满足离开 \(A\) 的次数等于回到 \(A\) 的次数。这个性质,几乎是完美契合这道题了。

但是问题是,我们如何进行建图呢?不难意识到,这题的“路径”是一个很重要的点。连 \((s_i,t_i)\) 因此是一个可行的想法。而我们同样还可以这样想:我们考虑割 \((S,V-S)\),其中 \(S\) 是一棵完整子树,其根为 \(u\),那么对于 \(fa_u\) 连向 \(u\) 的边,就是从 \(S\) 出去的路径 和 从 \(V-S\) 回来的路径啊。那我不直接只对着 \((s_i,t_i)\) 建边就好了?

但是显然我们不一定能构成欧拉回路,考虑直接贷一条边,那么我们自然是直接贷树边的,不难发现这样子我们最多会多算一次,和我们的理念契合。

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 4e3 + 10;
int n,m;
vector<int> G[N];

vector<int> E[N];
int eu[N],ev[N],used[N],f[N],cnt,deg[N];
int s[N],t[N];
void add(int u,int v,int w){
	cnt ++ ;
	eu[cnt] = u,ev[cnt] = v,f[cnt] = w;
	deg[u] ++ ;deg[v] ++ ;
	E[u].push_back(cnt);E[v].push_back(cnt);
}

int fa[N],siz[N],dfn[N],idfn[N],son[N],top[N],dep[N],tot;
void dfs(int u,int rt){
	fa[u] = rt;
	siz[u] = 1;
	dep[u] = dep[rt] + 1;
	for(int v : G[u]){
		if(v == rt) continue;
		dfs(v,u);
		if(siz[v] > siz[son[u]]) son[u] = v;
		siz[u] += siz[v];
	}
	return ;
}
void dfs2(int u,int tp){
	dfn[u] = ++tot;idfn[tot] = u;
	top[u] = tp;
	if(son[u]) dfs2(son[u],tp);
	for(int v : G[u]){
		if(v == fa[u] || v == son[u]) continue;
		dfs2(v,v);
	}
}
int LCA(int u,int v){
	while(top[u] != top[v]){
		if(dep[top[u]] > dep[top[v]]) swap(u,v);
		v = fa[top[v]];
	}
	return (dep[u] < dep[v]) ? u : v;
}

int d[N];
int ans = 0;
void init(int u){
	for(int v : G[u]){
		if(v == fa[u]) continue;
		init(v);
		d[u] += d[v];
	}
	ans += min(2,d[u]);
}

void solve(int u){
	while(!E[u].empty()){
		int i = E[u].back();
		E[u].pop_back();
		if(used[i]) continue;
		used[i] = 1;
		int v = eu[i] ^ ev[i] ^ u;
		if(f[i])
			if(u != s[f[i]]) swap(s[f[i]],t[f[i]]);
		solve(v);
	}
}
int main(){
	IOS;
	cin >> n >> m;
	for(int i=1;i<n;i++){
		int u,v;
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1,0); dfs2(1,1);
	for(int i=1;i<=m;i++){
		cin >> s[i] >> t[i];
		add(s[i],t[i],i);
		d[s[i]] ++ ;
		d[t[i]] ++ ;
		d[LCA(s[i],t[i])] -= 2;
	}
	init(1);

	for(int i=n;i>=1;i--){
		int u = idfn[i];
		if(deg[u] % 2 == 1)
			add(fa[u],u,0);
	}

	for(int i=1;i<=n;i++)
		solve(i);
	cout << ans << "\n";
	for(int i=1;i<=m;i++)
		cout << s[i] << " " << t[i] << "\n";
	return 0;
}
posted @ 2026-09-24 11:46  WinterXorSnow  阅读(8)  评论(0)    收藏  举报