Description

  

​   给一棵\(n\)个节点的树,和一个长度同样为\(n\)的非负整数序列\(x_i\)。

  

​   请尝试对每个节点染黑或白两种颜色,并确定一个非负整数权值。

  

​   问是否存在一种方案,使得每个点\(i\)满足其子树内与其同色的点的权值之和恰好为\(x_i\)。

  

​   \(1 \le n \le 1000\)

  

  ​ \(0 \le x_i \le 5000\)

  

  

  

Solution

  

​   一道好题。

  

​   我们自底向上逐步确定权值。假设当前正在考虑\(u\)这个点。

  

​   我们发现,\(u\)本身选黑还是白并不重要,其子树中的点只有两种:颜色和\(u\)相同的点,以及颜色和\(u\)不相同的点。

  

​   能确定的是,前一类的点的权值值和必须恰好等于\(x_u\),而在这个条件下,后者的点的权值值和可以有多种情况。

  

​   回头看一下,对于一种合法方案,单看每一种颜色形成的树的话,每个点\(u\)都要满足“后继”(单看一个颜色形成的树意义下的后继)的\(x\)之和小于等于\(x_u\),这样一来\(u\)的权值可以设为一个恰好的值,使得和调整为\(x_u\)。

  

​   显然我们可以对每个点\(u\)维护一个值\(f_u\),表示在满足与\(u\)颜色相同的点的权值值和恰好为\(x_u\)时,与\(u\)颜色不同的点的权值之和最小是多少。这是一个贪心的思想,由于一种颜色的权值和只能是\(x_u\),因此我们尽量保证另一种颜色的权值之和最小,以最大化这种颜色在之后考虑父亲节点时满足“小于等于”的可能性。

  

​   设\(g_i\)表示当前与\(u\)同色权值值和为\(i\)时,另一个颜色的最小值是多少。

  

​   初始有\(g_0=0, g_{i}=\infty (i>0)\)

  

​   对于每个后继\(v\),转移

\[g_i+f_v\rightarrow g_{i+x_v}\\g_i+x_v\rightarrow g_{i+f_v}
\]

​   注意是非继承转移,每层转移前每个位置都是\(\infty\)。

  

​   最后\(f_u=\min g_i\;\;(0 \le i \le x_u)\)

  

​   如果$f_1=\infty $就无解,否则有解。

    

​   此题关键是想到贪心的那一步。如果不贪心的话,相当于每个点有多个状态(另一个颜色有多种和)等待转移,根本做不了。

  

​  

  

  

  

Code

  

#include <cstdio>
using namespace std;
const int N=1005,X=5005,INF=1e9;
int n,a[N];
int f[N],g1[X],g2[X];
int h[N],tot;
struct Edge{int v,next;}e[N*2];
inline void addEdge(int u,int v){
e[++tot]=(Edge){v,h[u]}; h[u]=tot;
e[++tot]=(Edge){u,h[v]}; h[v]=tot;
}
inline int min(int x,int y){return x<y?x:y;}
void readData(){
scanf("%d",&n);
int fa;
for(int i=2;i<=n;i++){
scanf("%d",&fa);
addEdge(fa,i);
}
for(int i=1;i<=n;i++) scanf("%d",a+i);
}
void dfs(int u,int fa){
bool have=false;
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa){
have=true;
dfs(v,u);
}
if(!have){
f[u]=0;
return;
}
for(int i=0;i<=a[u];i++) g1[i]=INF;
g1[0]=0;
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa){
for(int j=0;j<=a[u];j++) g2[j]=INF;
for(int j=0;j<=a[u]&&(j+a[v]<=a[u]||j+f[v]<=a[u]);j++)
if(g1[j]!=INF){
if(j+a[v]<=a[u])
g2[j+a[v]]=min(g2[j+a[v]],g1[j]+f[v]);
if(j+f[v]<=a[u])
g2[j+f[v]]=min(g2[j+f[v]],g1[j]+a[v]);
}
for(int j=0;j<=a[u];j++) g1[j]=g2[j];
}
f[u]=INF;
for(int i=0;i<=a[u];i++) f[u]=min(f[u],g1[i]);
}
int main(){
readData();
dfs(1,0);
puts(f[1]==INF?"IMPOSSIBLE":"POSSIBLE");
return 0;
}

【ARC083E】Bichrome Tree的更多相关文章

  1. 【ARC083E】Bichrome Tree 树形dp

    Description 有一颗N个节点的树,其中1号节点是整棵树的根节点,而对于第ii个点(2≤i≤N)(2≤i≤N),其父节点为PiPi 对于这棵树上每一个节点Snuke将会钦定一种颜色(黑或白), ...

  2. 【BZOJ】2631: tree LCT

    [题意]给定n个点的树,每个点初始权值为1,m次操作:1.x到y的点加值,2.断一条边并连一条边,保证仍是树,3.x到y的点乘值,4.x到y的点权值和取模.n,m<=10^5. [算法]Link ...

  3. 【BZOJ2212】[Poi2011]Tree Rotations 线段树合并

    [BZOJ2212][Poi2011]Tree Rotations Description Byteasar the gardener is growing a rare tree called Ro ...

  4. 【题解】Digit Tree

    [题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...

  5. 【题解】[P4178 Tree]

    [题解]P4178 Tree 一道点分治模板好题 不知道是不是我见到的题目太少了,为什么这种题目都是暴力开值域的桶QAQ?? 问点对,考虑点分治吧.直接用值域树状数组开下来,统计的时候直接往树状数组里 ...

  6. 【总结】Link-Cut Tree

    这是一篇关于LCT的总结 加删边的好朋友--Link Cut Tree Link-Cut Tree,LCT的全称 可以说是从树剖引出的问题 树剖可以解决静态的修改或查询树的链上信息:那如果图会不断改变 ...

  7. 【BZOJ】1468: Tree(POJ1741) 点分治

    [题意]给定带边权树,求两点距离<=k的点对数.n<=40000. [算法]点分治 [题解]对于一个区域,选择其重心x作为根,则划分出来的每棵子树都是子区域,可以证明至多划分log n次( ...

  8. 【题解】【BT】【Leetcode】Binary Tree Preorder/Inorder/Postorder (Iterative Solution)

    [Inorder Traversal] Given a binary tree, return the inorder traversal of its nodes' values. For exam ...

  9. 【Leetcode】【Easy】Binary Tree Level Order Traversal II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

随机推荐

  1. 洛谷P1585 魔法阵

    题目传送门 这题就是一个有技巧的DFS+一大堆乱七八糟的剪枝 进行DFS时注意一下以下点 根据题意,我们可以把DFS分成两块,即1--n*m/2与n*m/2--n*m,第一块边找边记录,第二块就开始计 ...

  2. Catlike学习笔记(1.2)-使用Unity画函数图像

    『Catlike系列教程』第二篇来了~今天周六,早上(上午11点)醒来去超市买了一周的零食回来以后就玩了一整天游戏非常有负罪感.现在晚上九点天还亮着感觉像下午7点左右的样子好像还不是很晚...所以就写 ...

  3. Shuffle Bags让你的随机不那么随机

    前言 当我最初写游戏时,我经常使用标准Random()函数,然后写一堆if和else条件来我获得预期结果.如果结果不太好,我会写更多的条件进行过滤或者筛选,直到我觉得游戏变得有趣.最近我发现有更好的方 ...

  4. 32bit GM命令

    GM 命令[32位服务端GM命令] //announce message this basicly tells a announcement on the whole server.. you can ...

  5. ovs源码阅读--netlink使用

    netlink netlink socket是一种用于用户态进程和内核态进程之间的通信机制.它通过为内核模块提供一组特殊的API,并为用户程序提供了一组标准的socket接口的方式,实现了全双工的通讯 ...

  6. ubuntu16.04 CUDA, CUDNN 安装

    这次介绍的是使用 tensorflow1.8, cuda9.0, cudnn7.0的版本 https://developer.nvidia.com/cuda-90-download-archive 下 ...

  7. 从一个简单的寻路问题深入Q-learning

    这第一篇随笔实际上在我的科学网博客上是首发,我重新拿到博客园再发一次是希望以此作为我学习Q-learning的一个新的开始.以后这边主技术,科学网博客主理论.我也会将科学网那边技术类的文章转过来的.希 ...

  8. Windows环境下,从零开始搭建Nodejs+Express+Ejs框架(二)---安装Express,ejs

    安装Express,ejs的前提是一定要先安装nodejs,具体安装方法请查看 http://www.cnblogs.com/tfiremeteor/p/8973105.html 安装Express和 ...

  9. oozie-ext

    安装oozie的时候需要ext的包支持,网站上找了一遍不是没有就是这个csdn下载还需要币,麻蛋...下面给出这个链接,在百度云上,如果失效了,在评论区或者给我留言,再发,一下是ext2.2.zip ...

  10. Vue 入门之数据绑定

    什么是双向绑定? Vue 框架很核心的功能就是双向的数据绑定. 双向是指:HTML 标签数据 绑定到 Vue 对象,另外反方向数据也是绑定的.通俗点说就是,Vue 对象的改变会直接影响到 HTML 的 ...