题解:P11562 【MX-X7-T3】[LSOT-3] 寄存器
这一道题的 subtask 给了很多线索。先跳过用来打暴力的第一个子任务,我们从第二个子任务开始观察。
第二个子任务有
考虑如下例子:
1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1
发现一段连续的相同的段,我们肯定会一起操作。因此我们可以把它简化成:
1 0 1 0 1 0 1
这时我们有两种选择,第一种是直接每次操作
接下来考虑第三个子任务,发现这个和我们刚刚考虑的情况很相似,即把联通的一大块看成一个点。但这时会发现我们刚刚只操作
若沿用之前的思路,那这个图需要四次操作。不过我们发现这个图可以这样操作:
- 翻转整个图。
- 断开下面三个
1 的边,再翻转整个图。 - 翻转根节点,即顶部的
1 。
我们发现,对于树只需要操作它的层数次即可。
不过层数该怎么求呢?首先发现假如
这时只需最小化最长的链。这时可以用树的直径的思路。找出从
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n;
int a[1000005]={114514};
vector<int> adj[1000005];
int maxp,maxd;
void dfs(int cur,int par,int deep){
if (a[cur]!=a[par]) deep++;
if (a[cur]==1&&deep>maxd) {
maxd=deep;
maxp=cur;
}
for (int i:adj[cur]) if (i!=par) dfs(i,cur,deep);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(nullptr);
cin>>n;
bool noone=true; // 特判一波全为0
for (int i=1;i<=n;i++) {
cin>>a[i];
if (a[i]==1) noone=false;
}
if (noone){
cout<<0;
return 0;
}
for (int i=1;i<n;i++){
int u,v;
cin>>u>>v;
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs(1,0,0);
maxd=0;
dfs(maxp,0,0);
cout<<(maxd+1)/2;
return 0;
}