Description

  

   给定一棵\(n\)个点的树,其中若干个点的权值已经给出。现在请为剩余点填入一个值,使得相邻两个点的差的绝对值恰好为1。请判断能否实现,如果能,请将方案一并输出。

  

  

  

Solution

  

   卡了一会,终于想出来了。

  

   首先从深度奇偶性和权值奇偶性这一方面考虑:如果所有已知点的权值与深度的奇偶性关系不全一样,则一定无解。

  

   然后考虑怎么构造。如果用已填点将树分成若干块,显然每一块是独立的,现在考虑单独一块。

  

   直接想有一点困难,所以我们先尝试考虑每一个空点\(u\)能填什么数:考虑这一个块中的一个有值点,其权值为\(x\),如果它到\(u\)距离为\(2k\),那么\(u\)的填数选择就有\(x-2k,x-2k+2,...,x,...,x+2k-1,x+2k\);如果它到\(u\)距离为\(2k+1\),那么\(u\)的填数选择就有\(x-2k-1,x-2k+1,x-2k+3...,x+2k-1,x+2k+1\)。

  

   考虑所有的有值点,那么\(u\)的取值范围就是这些选择的交\(S\)。也就是说,只要\(u\)填\(S\)中的权值,单看\(u\)而言就一定能填出满足所有有值点的方案。若\(S\)为空则全局无解。

  

   可是对于每个空点,我们到底选\(S\)中的哪个权值填入呢?注意到如果随便填的话,可能会出现跳跃的问题。

  

   我画了几个例子。构造例子的方法是先弄一棵填好权值的合法树,再指定有值位置。当我用上述方法考虑空点的\(S\)时,我们发现:当且仅当将每一个点都取其\(S\)中的最小值时有解(或都取最大值),原问题才有解,这种填法即一种合法方案;否则无解。

  

   粗略证明:考虑一个点\(u\)的取值集合\(S\),它其实是一个范围\([l,r]\),但中间的取值是每隔1取一个的。对于任意一个与\(u\)相邻的点\(v\),记其权值范围为\([l',r']\),则其权值边界的跨度都不会超过1,即有\(l'=l\pm1\)和\(r'=r \pm1\),注意两者不是互不相关的。为什么?\(S\)记录的是每一个有值点\(x\)到这个点对应的权值范围的交。走多一步,意味着空隙翻转(原来是跳一次取一次的),对于走近了的\(x\),其权值范围以\(x\)为中心向内空隙翻转,对于走远了的\(x\),其权值范围向外空隙翻转;也就是一个多了两端,一个少了两端。仔细分析下来,\(S\)的边界变化也不会超过1.

  

   如果有解,那么这样填数一定能够满足条件------我们是贴着边界走的,而有值点本身也在边界上。如果这样填都不能满足,显然全局无解。

  

   因此我们对每个点取\(S\)的最小值,判断是否合法即可。

  

   至于\(S\)最小值的计算方法,这里有一个技巧:对于每个点\(u\),我们直接维护所有有值点\(x\)对应的范围的左端点的最大值,即\(x-dis\)的最大值。这样一来,如果真正意义上\(S\)交集不为空,那么这个值就是\(u\)的取值。否则,这个值无论如何都会使得后面的判定出错不合法,毕竟取值不满足所有的有值点。

     

    

Code

#include <cstdio>
#include <cstring>
using namespace std;
const int N=100005;
const int INF=1e9;
int n,m;
int a[N];
int h[N],tot,dep[N];
struct Edge{
int v,next;
}e[N*2];
int f[N],g[N],ans[N];
inline int max(int x,int y){
return x>y?x:y;
}
inline int abs(int x){
return x>=0?x:-x;
}
void addEdge(int u,int v){
e[++tot]=(Edge){v,h[u]}; h[u]=tot;
e[++tot]=(Edge){u,h[v]}; h[v]=tot;
}
void readData(){
scanf("%d",&n);
int u,v;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addEdge(u,v);
}
memset(a,-1,sizeof a);
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
a[u]=v;
}
}
void mark_dfs(int u,int fa){
dep[u]=dep[fa]+1;
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa)
mark_dfs(v,u);
}
bool firstCheck(){
mark_dfs(1,0);
int flag=-1;
for(int u=1;u<=n;u++)
if(a[u]!=-1){
if(flag==-1)
flag=(a[u]^dep[u])&1;
else if(((a[u]^dep[u])&1)!=flag)
return false;
}
return true;
}
void dp_dfs1(int u,int fa){
f[u]=(a[u]!=-1)?a[u]:-INF;
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa){
dp_dfs1(v,u);
f[u]=max(f[u],f[v]-1);
}
}
bool dp_dfs2(int u,int fa){
if(a[u]!=-1)
g[u]=a[u];
ans[u]=(a[u]!=-1)?a[u]:max(f[u],g[u]);
if(fa&&abs(ans[u]-ans[fa])!=1)
return false;
static int ch[N],cnt;
static int l[N],r[N];
cnt=0;
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa)
ch[++cnt]=v;
l[0]=g[u]+1; r[cnt+1]=-INF;
for(int i=1;i<=cnt;i++)
l[i]=max(l[i-1],f[ch[i]]);
for(int i=cnt;i>=1;i--)
r[i]=max(r[i+1],f[ch[i]]);
for(int i=1;i<=cnt;i++)
g[ch[i]]=max(l[i-1],r[i+1])-2;
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa){
if(dp_dfs2(v,u)==false)
return false;
if(abs(ans[u]-ans[v])!=1)
return false;
}
return true;
}
bool solve(){
dp_dfs1(1,0);
g[1]=-INF;
if(dp_dfs2(1,0)==false)
return false;
puts("Yes");
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return true;
}
int main(){
readData();
if(!firstCheck()||!solve()){
puts("No");
return 0;
}
return 0;
}

【ARC063E】Integers on a tree的更多相关文章

  1. 【BZOJ2959】长跑(Link-Cut Tree,并查集)

    [BZOJ2959]长跑(Link-Cut Tree,并查集) 题面 BZOJ 题解 如果保证不出现环的话 妥妥的\(LCT\)傻逼题 现在可能会出现环 环有什么影响? 那就可以沿着环把所有点全部走一 ...

  2. 【BZOJ2588】Count On a Tree(主席树)

    [BZOJ2588]Count On a Tree(主席树) 题面 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第 ...

  3. 【BZOJ2816】【ZJOI2012】网络(Link-Cut Tree)

    [BZOJ2816][ZJOI2012]网络(Link-Cut Tree) 题面 题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相 ...

  4. 【CF434E】Furukawa Nagisa's Tree 点分治

    [CF434E]Furukawa Nagisa's Tree 题意:一棵n个点的树,点有点权.定义$G(a,b)$表示:我们将树上从a走到b经过的点都拿出来,设这些点的点权分别为$z_0,z_1... ...

  5. 【CF725G】Messages on a Tree 树链剖分+线段树

    [CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...

  6. 【SPOJ】QTREE7(Link-Cut Tree)

    [SPOJ]QTREE7(Link-Cut Tree) 题面 洛谷 Vjudge 题解 和QTREE6的本质是一样的:维护同色联通块 那么,QTREE6同理,对于两种颜色分别维护一棵\(LCT\) 每 ...

  7. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

  8. 【BZOJ2870】最长道路tree 点分治+树状数组

    [BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...

  9. 【数据挖掘】分类之decision tree(转载)

    [数据挖掘]分类之decision tree. 1. ID3 算法 ID3 算法是一种典型的决策树(decision tree)算法,C4.5, CART都是在其基础上发展而来.决策树的叶子节点表示类 ...

随机推荐

  1. Jenkins日常运维笔记-重启数据覆盖问题、迁移、基于java代码发版(maven构建)

    之前在公司机房部署了一套jenkins环境,现需要迁移至IDC机房服务器上,迁移过程中记录了一些细节:1)jenkins默认的主目录放在当前用户家目录路径下的.jenkins目录中.如jenkins使 ...

  2. Pair Project —— Elevator Scheduler

    结对编程人员 12061153 刘丽萍 12061154 冯飘飘 说明结对编程的优点和缺点. 结对编程的优点: 以前都是自己一个人编程,对于相互结对或者团队编程都没有接触过.而自己在写代码时不可避免的 ...

  3. linux第三次读书笔记

    第七章:链接 一.编译器驱动程序 编译系统提供的调用预处理器.编译器.汇编器和链接器来构造目标文件的程序. 二.静态链接 三.目标文件 三种形式: 1.可重定位目标文件: 2.可执行目标文件: 3.共 ...

  4. 《Linux内核设计与实现》 第八周读书笔记 第四章 进程调度

    20135307 张嘉琪 第八周读书笔记 第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有 ...

  5. Linux内核读书笔记第三周 调试

    内核调试的难点在于它不能像用户态程序调试那样打断点,随时暂停查看各个变量的状态. 也不能像用户态程序那样崩溃后迅速的重启,恢复初始状态. 用户态程序和内核交互,用户态程序的各种状态,错误等可以由内核来 ...

  6. 最新广商小助手 项目进展 OpenGL ES 3D在我项目中引用 代码太多只好选重要部分出来

    package com.example.home; import java.io.IOException; import java.io.InputStream; import javax.micro ...

  7. Daily Scrum- 12/28

    Meeting Minutes 讨论alpha 的feed back; 决定添加按钮向下的动作,作为feature; 完成了界面的微调,开始使用alpha.1进行feed back的收集 Burndo ...

  8. vue中eventbus被多次触发(vue中使用eventbus踩过的坑)【bus.$on事件被多次绑定】

    问题描述:只要页面没有强制刷新,存在组件切换,bus.$on方法会被多次绑定,造成事件多次触发   触发bus.$on中绑定的方法.png   bus.$on多次绑定.png 解决办法:在每次调用方法 ...

  9. wx.downloadFile问题

    http://www.wxapp-union.com/forum.php?mod=viewthread&tid=2988(copy) 这个问题,研究者甚少,以至于相关问题直到今天,仍然属于未知 ...

  10. OpenJS Foundation

    OpenJS Foundation Introducing the OpenJS Foundation https://openjsf.org/ The Node.js Foundation and ...