洛谷 P7163 - [COCI2020-2021#2] Svjetlo(树形 dp)
神仙级别的树形 dp。
u1s1 这种代码很短但巨难理解的题简直是我的梦魇
首先这种题目一看就非常可以 DP 的样子,但直接一维状态的 DP 显然无法表示所有情况。注意到对于这类统计一个路径上权值之和的最值这样的问题,我们可以考虑借鉴 P4383 林克卡特树 的套路,即在 DP 状态中多记录一维 \(j\) 存储当前路径的延伸情况。但是这道题与 林克卡特树 的不同之处在于路径并非是简单路径,即一条路径可以先向上走一段,再向下走一段,接着再向上走一段。因此考虑这样设计 DP 状态:我们考察路径的起点和终点 \(x,y\),并设 \(dp_{u,j,k}\) 表示目前 \(u\) 考虑到 \(u\) 的子树,\(x,y\) 中恰好有 \(j\) 个在 \(u\) 的子树中 \((j\in[0,2])\),目前除了 \(u\) 的状态为 \(k\) 之外,\(u\) 子树内其剩余所有点的状态都变为 \(1\) 的最短序列长度。
初始三种情况都只有一条单一的 \(u\to u\) 的路径,即 \(dp_{u,0,a_u\oplus 1}=dp_{u,1,a_u\oplus 1}=dp_{u,2,a_u\oplus 1}=1\)。考虑怎样合并两棵子树的路径,即从 \(dp_{u,j,k}\) 与 \(dp_{v,p,q}\) 推出新的 \(dp_{u,j,k}\),其中 \(u\) 的 \(v\) 的父亲,\(p+j\le 2\)。这一部分的转移略有亿点点恶心,下面将分条叙述:
- 若 \(p=1\),那么 \(v\) 子树内的路径应当是一条不能再向下延伸,但可以再继续向上延伸的路径 \(x\to v\),同理由于 \(p+q\le 2\),\(u\) 子树内对应的路径必然有一个端点会向上延伸,即一条 \(u\to y\) 的路径,其中 \(y\) 可以等于 \(u\),即 \(j=0\) 的情况,也可以不等于 \(u\),即 \(j=1\) 的情况,那么:
- 如果 \(k=1\),那么此时直接将两部分拼在一起即可,即 \(x\to v\to u\to y\),\(dp_{u,j,k}+dp_{v,p,q}\to newdp_{u,j+p,q}\)
- 如果 \(k=0\),那么在合并时候还要花费 \(2\) 的代价将 \(y\) 的状态变为 \(1\),即 \(x\to v\to u\to v\to u\to y\),此时 \(y\) 的状态也会改变,\(dp_{u,j,k}+dp_{v,p,q}+2\to newdp_{u,j+p,q\oplus 1}\)
- 若 \(p=2\),那么 \(v\) 子树内的路径本来应是一段 \(x\to y\),而 \(u\) 子树内的路径应为一段 \(u\to u\) 的回路,那么合并两段路径时,由于本来经过 \(v\) 的是一段完整的路径 \(x\to y\),而现在我们要将 \(u\to u\) 的路径嵌进去,因此我们要将 \(x\to y\) 的路径拆成 \(x\to v\) 和 \(v\to y\),然后将两段按 \(x\to v\to u\to u\to v\to x\) 的顺序合并,至于额外代价……首先将两个 \(v\) 拆开来需要有 \(1\) 的代价。其次如果 \(k=1\),那么合并时将 \(v\) 拆成了两段会将 \(v\) 的状态改变一次,变成 \(0\),此时我们还需要在 \(u,v\) 反复横跳一次之后才能将 \(v\) 的状态变为 \(1\)。而如果 \(k=0\),则不需要,因此:
- 如果 \(k=1\),那么 \(dp_{u,j,k}+dp_{v,p,q}\to newdp_{u,j+p,q\oplus 1}+3\)
- 如果 \(k=0\),那么 \(dp_{u,j,k}+dp_{v,p,q}\to newdp_{u,j+p,q}+1\)
- 若 \(p=0\),那么 \(v\) 子树内的路径就是一段回路 \(v\to v\),我们合并两条路径时,由于两个 \(v\) 都要向上延伸,因此我们要将 \(u\) 子树内一段路径拆成两段 \(x\to u\) 和 \(y\to u\),然后将 \(v\to v\) 嵌进去,即 \(x\to u\to v\to v\to u\to y\),这样 \(u\) 的状态首先会改变一次,产生 \(1\) 的基本代价,而:
- 如果 \(k=1\),那不用额外代价,但 \(u\) 的状态会改变 \(1\),\(dp_{u,j,k}+dp_{v,p,q}\to newdp_{u,j+p,q\oplus 1}+1\)
- 如果 \(k=0\),那还要在 \((u,v)\) 上反复横跳一次将 \(v\) 的状态改为 \(1\),同时 \(u\) 的状态又改变了一次,这样一来一回贡献抵消了,因此 \(dp_{u,j,k}+dp_{v,p,q}\to newdp_{u,j+p,q}+3\)
状态转移情况就这么多。注意一些细节的情况,比方说一个子树如果所有点的状态都是 \(1\),那我们大可不必进入这个子树,直接 continue 即可,还有就是要以一个 \(s_i='0'\) 的点为根 DFS。
总复杂度 \(\mathcal O(n)\)
const int MAXN=5e5;
int n,a[MAXN+5],rt=-1;char s[MAXN+5];
int hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int sum[MAXN+5],dp[MAXN+5][3][2];
void dfs(int x,int f){
sum[x]=(!a[x]);
dp[x][0][a[x]^1]=dp[x][1][a[x]^1]=dp[x][2][a[x]^1]=1;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f) continue;dfs(y,x);
sum[x]|=sum[y];if(!sum[y]) continue;
static int tmp[3][2];memset(tmp,63,sizeof(tmp));
for(int i=0;i<2;i++) for(int j=0;j<2;j++)
for(int p=0;p<3;p++) for(int q=0;p+q<3;q++){
if(q==0) chkmin(tmp[p+q][i^j],dp[x][p][i]+dp[y][q][j]+3-j*2);
if(q==1) chkmin(tmp[p+q][i^j^1],dp[x][p][i]+dp[y][q][j]+2-j*2);
if(q==2) chkmin(tmp[p+q][i^j],dp[x][p][i]+dp[y][q][j]+3-(j^1)*2);
}
memcpy(dp[x],tmp,sizeof(dp[x]));
}
}
int main(){
scanf("%d%s",&n,s+1);
for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
for(int i=1;i<=n;i++) a[i]=s[i]-'0';
for(int i=1;i<=n;i++) if(!a[i]) rt=i;
memset(dp,63,sizeof(dp));
dfs(rt,0);printf("%d\n",dp[rt][2][1]);
return 0;
}
洛谷 P7163 - [COCI2020-2021#2] Svjetlo(树形 dp)的更多相关文章
- 洛谷 P2015 二叉苹果树(codevs5565) 树形dp入门
dp这一方面的题我都不是很会,所以来练(xue)习(xi),大概把这题弄懂了. 树形dp就是在原本线性上dp改成了在 '树' 这个数据结构上dp. 一般来说,树形dp利用dfs在回溯时进行更新,使用儿 ...
- 洛谷 P3267 - [JLOI2016/SHOI2016]侦察守卫(树形 dp)
洛谷题面传送门 经典题一道,下次就称这种"覆盖距离不超过 xxx 的树形 dp"为<侦察守卫模型> 我们考虑树形 \(dp\),设 \(f_{x,j}\) 表示钦定了 ...
- 洛谷P1352 没有上司的舞会——树形DP
第一次自己写树形DP的题,发个博客纪念`- 题目来源:P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结 ...
- 洛谷 P1453 城市环路 ( 基环树树形dp )
题目链接 题目背景 一座城市,往往会被人们划分为几个区域,例如住宅区.商业区.工业区等等.B市就被分为了以下的两个区域--城市中心和城市郊区.在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市 ...
- 洛谷 P2986 [USACO10MAR]Great Cow Gat…(树形dp+容斥原理)
P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat… 题目描述 Bessie is planning the annual Great Cow Gathering for c ...
- C++ 洛谷 P2458 [SDOI2006]保安站岗 from_树形DP
P2458 [SDOI2006]保安站岗 没学树形DP的,看一下. 题目大意:一棵树有N个节点,现在需要将所有节点都看守住,如果我们选择了节点i,那么节点i本身,节点i的父亲和儿子都会被看守住. 每个 ...
- 洛谷P2279 消防局的设立【树形dp】
题目:https://www.luogu.org/problemnew/show/P2279 题意:一棵树.在节点处建消防站,可以覆盖与他距离在2之内的节点.问最少要建多少个消防站,可以覆盖所有的节点 ...
- 洛谷P3177 [HAOI2015]树上染色(树形dp)
题目描述 有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所有点染色后,你会获得黑点两两之 ...
- 洛谷 P1352 没有上司的舞会 树形DP板子
luogu传送门 题目描述: 某大学有n个职员,编号为1~n. 他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司. 现在有个周年庆宴会,宴会每邀请来一个职员都会 ...
- 2018.07.22 洛谷P3047附近的牛(树形dp)
传送门 给出一棵n" role="presentation" style="position: relative;">nn个点的树,每个点上有C ...
随机推荐
- LDAP-初见
目录 什么是LDAP? LDAP 协议能解决什么问题? Spring Boot中使用LDAP来统一管理用户信息 添加用户 连接LDAP服务端 什么是LDAP? LDAP 的全称是 Lightweigh ...
- 什么是Spring,SpringMVC,SpringBoot,SpringCloud?通俗易懂
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架.Spring使你能够编写更干净.更可管理.并且更易于测试的代码. Spring MVC是Spring的一个模块,一个web框 ...
- 天脉2(ACoreOS653)操作系统学习02
天脉2(ACoreOS653)操作系统学习02 一.分区内通信方法 分区内通信指同一分区内进程之间的通信.ARINC 653定义的分区内进程通信机制,包括:缓存队列(Buffers-Queue).黑板 ...
- 测试小姐姐问我 gRPC 怎么用,我直接把这篇文章甩给了她
原文链接: 测试小姐姐问我 gRPC 怎么用,我直接把这篇文章甩给了她 上篇文章 gRPC,爆赞 直接爆了,内容主要包括:简单的 gRPC 服务,流处理模式,验证器,Token 认证和证书认证. 在多 ...
- 第六次Alpha Scrum Meeting
本次会议为Alpha阶段第六次Scrum Meeting会议 会议概要 会议时间:2021年5月2日 会议地点:线上会议 会议时长:20min 会议内容简介:本次会议主要由每个人展示自己目前完成的工作 ...
- 电脑cmd命令快速查看连接过的WIFI密码信息
只是突然发现,好奇心作怪,试了一下,妈妈再也不用担心我忘记家里的wifi密码了 1.直接打开"运行"(win键+R) 2.输入CMD 确定 3.输入下面cmd命令.鼠标粘贴 for ...
- cat userlist(课上练习)
问题描述 Linux文件系统的三层抽象是什么? 写出Cat userlist的过程,要详述目录文件,i-node.数据块,要画图示意. 假设块大小为4k, userlist的大小不小于10k,自己假设 ...
- [转]DDR内存条rank的概念和区分
1:什么是RANK? 答:CPU与内存之间的接口位宽是64bit,也就意味着CPU在一个时钟周期内会向内存发送或从内存读取64bit的数据.可是,单个内存颗粒的位宽仅有4bit.8bit或16bit, ...
- AXI协议中的模棱两可的含义的解释(Cachable和Bufferable)
转载:https://blog.csdn.net/hit_shaoqi/article/details/53243173 Cachable和Bufferable 一个Master发出一个读写的requ ...
- 最后的OI(HAOI2020游记)
马上就省选了,怎么不得写点什么?要不然到最后或许就真的落得个白茫茫大地真干净的局面. 其实也不知道该说啥?我这一路走来,感觉挺赚的. 每一个OIer背后都有一个故事,所以,我有故事,你有酒吗? 依稀记 ...