CF1824C 题解
题目大意
给定一棵
思路
首先只要让整棵树的各条根到叶子节点的异或和变成相等的,最后调节根节点
所以现在考虑子树
这里我们记录数组
回归正题,每次我们显然儿子
然后最后在判断一下需不需要调节
实现方面可以用 map 记录可以修改的值的集合,可以开多个 map,每次交换两个 map 的地址更新(实际上这里也是启发式合并,每次从别的儿子节点往信息最多的信息节点合并信息,刚开始蠢笨了)。具体看代码。
代码
#include <bits/stdc++.h>//祝大家学习愉快!
using namespace std;
const int maxn=1e5+5;
int a[maxn],id[maxn],n,res=0;
struct edge{
int to,nxt;
}e[maxn<<1];
int head[maxn],len;
map<int,int> mp[maxn],tmp;
inline void init(){
memset(head,-1,sizeof(head));
len=0;
}
void add(int u,int v){
e[++len].to=v;
e[len].nxt=head[u];
head[u]=len;
}
void dfs(int u,int f){
if(f&&e[head[u]].nxt==-1){
// printf("kkkk%d\n",u);
mp[id[u]][a[u]]++;
return;
}
int maxx=1,cnt=0;
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
if(v==f) continue;
a[v]^=a[u];
dfs(v,u);
if(mp[id[u]].size()<mp[id[v]].size()) swap(id[u],id[v]);
for(auto now : mp[id[v]]){
mp[id[u]][now.first]+=now.second;
maxx=max(maxx,mp[id[u]][now.first]);
}
cnt++;
}
res+=cnt-maxx;
// map<int,in>
tmp.clear();
if(maxx>1){
for(auto now : mp[id[u]]){
if(now.second==maxx) tmp[now.first]=1;
}
swap(mp[id[u]],tmp);
}
}
int main(){
int n;
init();
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
id[i]=i;
}
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,0);
printf("%d\n",res+(!mp[id[1]][0]));
return 0;
}