题解:P12895 [POI 2019/2020 R2] 假期 Wakacje Bajtazara
sunkuangzheng · · 题解
容易发现将树黑白染色后,可以游览的城市颜色相同,因此首先枚举黑白,将另一种颜色点权全部设置为
分析我们能走的点的形态,不难发现其实是“毛毛虫”状物,即一条链和到这条链距离为
求解最大权毛毛虫是经典套路,首先记一个点
最后输出方案是简单的,按顺序遍历直径输出旁边的点即可。复杂度线性。
/**
* author: sunkuangzheng
* created: 21.06.2025 14:37:44
**/
#include<bits/stdc++.h>
#ifdef DEBUG_LOCAL
#include <mydebug/debug.h>
#endif
using ll = long long;
const int N = 1e6+5;
using namespace std;
int T,n,a[N],u,v,c[N],w[N],fa[N]; vector<int> g[N]; ll f[N];
pair<ll,int> dp[N]; ll W; int du,dv;
void dfs1(int u,int f){
c[u] = c[f] ^ 1,fa[u] = f;
for(int v : g[u]) if(v != f) dfs1(v,u);
}void dfs2(int u){
if(w[u]) dp[u] = {w[u] + f[u],u}; else dp[u] = {-1e18,0};
for(int v : g[u]) if(v != fa[u]){
dfs2(v);
if(dp[u].first + dp[v].first > W)
W = dp[u].first + dp[v].first,
du = dp[u].second,dv = dp[v].second;
dp[u] = max(dp[u],{dp[v].first + f[u],dp[v].second});
}
}int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin >> n;
for(int i = 1;i <= n;i ++) cin >> a[i];
for(int i = 1;i < n;i ++) cin >> u >> v,g[u].push_back(v),g[v].push_back(u);
if(n <= 2){
cout << *max_element(a+1,a+n+1) << "\n";
cout << "1\n";
cout << max_element(a+1,a+n+1) - a << "\n";
return 0;
}dfs1(1,0);
for(int co : {0,1}){
for(int i = 1;i <= n;i ++) w[i] = (c[i] == co) * a[i];
for(int i = 1;i <= n;i ++){
f[i] = -w[i];
for(int j : g[i]) f[i] += w[j];
}dfs2(1);
// debug(W,du,dv);
// printarr(1,n,f);
}dfs1(du,0);
vector<int> p;
cout << W << "\n";
while(dv) p.push_back(dv),dv = fa[dv];
// if(p.size() % 2 == 0) p.pop_back();
assert(p.size() & 1);
vector<int> as;
for(int i = 0;i < p.size();i ++){
as.push_back(p[i]);
if(!(i & 1)) continue;
else{
for(int v : g[p[i]]) if(v != p[i-1] && v != p[i+1])
as.push_back(v),as.push_back(p[i]);
}
}//if(as.size() % 2 == 0) as.pop_back();
assert(as.size() % 2 == 1);
cout << (as.size() + 1) / 2 << "\n";
for(int v : as) cout << v << " ";
cout << "\n";
}