【题解】CF1626E Black and White Tree
题目分析:
因为要对每个点都进行求解,所以可以考虑换根 。
也就是我们先想想若给定根,怎么求解,我们发现点 若可以走到某一个黑色点,当且仅当它的某一个儿子可以走到这个黑色点且它可以走到它的儿子,而他能走到它的某一个儿子节点并经过儿子节点继续走,当且仅当它这个儿子的子树内有大于等于 个黑色点,这样就可以交替着走。
当然有一种特例就是它的某一个儿子就是黑色节点,这样直接走过去就好了。
那么直接 一遍就可以得到当前点的答案了。
这个题换根是容易的,因为只需要维护一个黑色节点数量和答案,就很简单了。
代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5+5;
const int MAXM = 1e6+5;
struct edge{
int nxt,to;
edge(){}
edge(int _nxt,int _to){
nxt = _nxt,to = _to;
}
}e[MAXM];
int cnt,head[MAXN],sz[MAXN],a[MAXN];
bool ans[MAXN];
void add_edge(int from,int to){
e[++cnt] = edge(head[from],to);
head[from] = cnt;
}
void dfs1(int now,int fa){
if(a[now]) ans[now] = true,ans[fa] = true;
sz[now] = a[now]; //这里的 sz 是指的黑点的数量
for(int i = head[now];i ;i = e[i].nxt){
int to = e[i].to;
if(to == fa) continue;
dfs1(to,now);
sz[now] += sz[to];
if(a[now]) ans[to] = true;
if(ans[to] && sz[to] >= 2) ans[now] = true;
}
}
void dfs2(int now,int fa){
for(int i = head[now]; i; i = e[i].nxt){
int to = e[i].to;
if(to == fa) continue;
if(sz[1] - sz[to] >= 2 && ans[now]) //这里不是很严谨,但是如果 now 可以经过 to 到达某一个黑点,那么显然 to 也可以,所以就没事了
ans[to] = true;
dfs2(to,now);
}
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n;
cin>>n;
for(int i=1; i<=n; i++){
cin>>a[i];
}
for(int i=1; i<n; i++){
int from,to;
cin>>from>>to;
add_edge(from,to);
add_edge(to,from);
}
dfs1(1,0); //第一遍 dp
dfs2(1,0); //换根
for(int i=1; i<=n; i++){
printf("%d ",ans[i]);
}
return 0;
}
标签:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律