题解 CF717E 【Paint it really, really dark gray】

MY(一名蒟蒻)

2021-02-15 12:29:58

题解

原题传送门

本题的难点主要是在定义递归结束后某个节点的状态。定义 \text{dfs(x)} 表示在递归完以 \text{x} 为根的子树把这个子树染黑后,停下来的点?显然非常不可做。

考虑定义 \text{dfs(x)} 表示从 \text{x} 开始走,最后回到 \text{x} ,将以 \text{x} 为根的子树中除了 \text{x} 以外的节点都变成黑色(\text{x} 的颜色可以任意)。

这样确定了递归后我们在什么位置,题目经过这样的转化变得可做起来。

这个 \text{x} 的颜色之后会由父亲处理。

那么如何dfs,或者说dfs的流程是怎样的呢?

这样做一遍后,除了根节点以外都是黑色,然后如果根是白色,找一个儿子(一定是黑色),过去-回来-过去然后结束路径即可。 容易证明这样构造的路径长度是可以接受的,大概是常数乘上 $\text{n}$ 。 时间复杂度 $\text{O(n)}$ , $\text{dfs}$ 时输出路径即可。 感觉思路已经说得非常清晰了,实现基本就是翻译一下。读者可以锻炼一下自己的码力。建议大家不看以下代码自己写出来。 ## Code ```cpp #include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <cstdlib> using namespace std; const int N=2e5+10; int n,fir[N],tot,col[N],fa[N]; struct node {int to,nex;} e[N << 1]; void add(int u,int v) { e[++tot].to=v; e[tot].nex=fir[u]; fir[u]=tot; return ; } void init(int x,int dad) { fa[x]=dad; for(int i=fir[x];i;i=e[i].nex) if(e[i].to^dad) init(e[i].to,x); return ; } void dfs(int x) { printf("%d ",x); for(int i=fir[x];i;i=e[i].nex) if(e[i].to^fa[x]) { col[e[i].to]^=1;//往子树走 dfs(e[i].to); printf("%d ",x); col[x]^=1;//回来 if(!col[e[i].to])//处理儿子颜色 { printf("%d %d ",e[i].to,x); col[e[i].to]=1; col[x]^=1; } } return ; } int main() { // freopen("work.in","r",stdin); freopen("work.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) {scanf("%d",&col[i]); if(col[i] < 0) col[i]=0;} for(int i=1,u,v;i<n;i++) {scanf("%d%d",&u,&v); add(u,v); add(v,u);} init(1,0); dfs(1); if(!col[1]) printf("%d 1 %d ",e[fir[1]].to,e[fir[1]].to);//最后的白点 // fclose(stdin); fclose(stdout); return 0; } ``` 难度建议蓝。 感谢阅读!您的评论和点赞是对作者最大的支持!