P4253 SCOI2015 小凸玩密室

一道紫色的 dp。

思路

首先读题:

要保证任意时刻所有被点亮的灯泡必须连通
在点亮一个灯泡后必须先点亮其子树所有灯泡才能点亮其他灯泡

考虑设 \(g[u][1]\) 为 \(u\) 子树第一个被选中的是子树的根的代价,\(g[u][0]\) 为 \(u\) 子树内第一个选中的点不是子树的根(全局第一个选中的点在 \(u\) 子树内且不为 \(u\))。

我们发现转移与距离有关,遂加一维。

设 \(g[u][1][j]\) 为 \(u\) 子树第一个被选中的是子树的根的代价,且 \(u\) 子树选完后,最后一个被选的点到 \(u\) 的距离为 \(j\)​。

\(g[u][0][j]\) 为 \(u\) 子树内第一个选中的点不是子树的根,且 \(u\) 子树选完后,最后一个被选的点到 \(u\) 的距离为 \(j\)。

反复思考题目中的两个条件,你会发现,每个子树内只有最后一个选中的是叶子节点才是合法情况。

但再思考一下,发现如果一个节点只有一个儿子,还是有可能自己成为子树内最后一个选中的节点。

不过这是一棵完全二叉树。

那么出现这种情况的点最多只会有一个,这种点特殊考虑就可以了。

我们可以写出一般情况下的二叉树转移方程:

设 \(v_1\)、\(v_2\) 为 \(u\) 的两个儿子,两条边的长度为 \(d[v_1]\) 和 \(d[v_2]\),\(dis[u]\) 为 \(u\) 子树中叶子节点到 \(u\) 节点的距离集合。

\[g[u][1][i+d[v_2]]=\min_{j\in dis[v_1]}(g[v_1][1][j]+a[v_2]\times (j+d[v_2]+d[v_1]))+g[v_2][1][i]+a[v_1]\times d[v_1]
\]

其中 \(i\in dis[v_2]\)。

这条方程的含义是:点亮 \(u\) 以后先去点亮 \(v_1\),再从 \(v_1\) 子树内的叶子节点点亮 \(v_2\),最后在 \(v_2\) 的叶子节点点完 \(u\) 子树,此时距离 \(v_2\) 节点是 \(i\),那么距离 \(u\) 节点就是 \(i+d[v_2]\)​ 了。

至于为什么都是 \(g[v][1][j]\) 在转移呢,因为父亲都子树内第一个点亮的了,那么想要点亮其它点肯定要先点亮儿子呀。

类似的可以写出:

\[g[u][1][i+d[v_1]]=\min_{j\in dis[v_2]}(g[v_2][1][j]+a[v_1]\times (j+d[v_1]+d[v_2]))+g[v_1][1][i]+a[v_2]\times d[v_2]
\]

其中 \(i\in dis[v_1]\)。

然后我们考虑针对 \(g[u][0][i]\) 的转移,此时自己的儿子可以是他所在子树内先点亮的,也可以是后点亮的,都是合法的,对于另外一个儿子肯定就是先点亮根的喽,那么有转移:

\[g[u][1][i+d[v_2]]=\min(\min_{j\in dis[v_1]}(g[v_1][0][j]+(j+d[v_1])\times a[u]),\min_{j\in dis[v_1]}(g[v_1][1][j]+(j+d[v1])\times a[u]))+d[v_2]\times a[v_2]+g[v_2][1][i]
\]

类似的我们需要把 \(v_1\) 和 \(v_2\) 换过来,在写一遍这个转移,下面就不再写了。

观察转移方程,注意到我们每个方程中含 \(j\) 的那一项,对于每一个 \(u\) 来说都是一个固定值。

所以每一次提前求出含 \(j\) 项的最小值,然后枚举 \(i\) 就可以转移了。

考虑时间复杂度:

每次转移都相当于遍历一遍自己子树内叶子节点到自己的距离。

所以每一层的转移复杂度都是 \(O(叶子节点个数)\)。

然而根据完全二叉树,层数不会超过 \(\log n\) 层,总复杂度就是 \(O(叶子节点个数 \log n)\)。

CODE

#include<bits/stdc++.h>
using namespace std; #define ll long long const int maxn=2e5+5; int n;
ll d[maxn],a[maxn]; vector<ll>vec[maxn],dis[maxn];
unordered_map<ll,ll>g[maxn][2]; inline void solve1(int u,int v1,int v2)//1 的转移
{
ll res=1e18;
for(auto j:dis[v1])//提前求含 j 项
res=min(res,g[v1][1][j]+a[v2]*(j+d[v2]+d[v1])+a[v1]*d[v1]);
for(auto j:dis[v2])
{
if(g[u][1][j+d[v2]]==0) g[u][1][j+d[v2]]=1e18;
g[u][1][j+d[v2]]=min(res+g[v2][1][j],g[u][1][j+d[v2]]);
}
}
inline void solve2(int u,int v1,int v2)//0 的转移
{
ll res0=1e18,res1=1e18;
for(auto j:dis[v1])
res0=min(res0,g[v1][0][j]+(j+d[v1])*a[u]+d[v2]*a[v2]),res1=min(res1,g[v1][1][j]+(j+d[v1])*a[u]+d[v2]*a[v2]);
for(auto j:dis[v2])
{
if(g[u][0][j+d[v2]]==0) g[u][0][j+d[v2]]=1e18;
g[u][0][j+d[v2]]=min(res0+g[v2][1][j],g[u][0][j+d[v2]]);
g[u][0][j+d[v2]]=min(res1+g[v2][1][j],g[u][0][j+d[v2]]);
}
}
inline void dfs(int u)
{
int v1=u*2,v2=u*2+1;
if(v1>n&&v2>n){vec[u].push_back(u);dis[u].push_back(0);return ;}
dfs(v1);
if(v2<=n) dfs(v2);
else
{
g[u][1][d[v1]]=d[v1]*a[v1];g[u][0][0]=d[v1]*a[u];
g[u][1][0]=1e18;g[u][0][d[v1]]=1e18;
vec[u].push_back(v1);vec[u].push_back(v2);dis[u].push_back(d[v1]);dis[u].push_back(0);
return ;
}
solve1(u,v1,v2);solve1(u,v2,v1);//v1,v2 转移方程是一样的
solve2(u,v1,v2);solve2(u,v2,v1);
vec[u].insert(vec[u].end(),vec[v1].begin(),vec[v1].end());
vec[u].insert(vec[u].end(),vec[v2].begin(),vec[v2].end());
dis[u].resize(vec[u].size());//处理 u 与叶子节点距离
for(int i=0;i<vec[v1].size();i++) dis[u][i]=dis[v1][i]+d[v1];
for(int i=0;i<vec[v2].size();i++) dis[u][i+vec[v1].size()]=dis[v2][i]+d[v2];
} int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=2;i<=n;i++) scanf("%lld",&d[i]);
dfs(1);
ll ans=1e18;
for(auto j:dis[1]) ans=min(ans,min(g[1][1][j],g[1][0][j]));
printf("%lld\n",ans);
}

后记

竟然是第一道独立做出来的紫色 dp。

P4253 SCOI2015 小凸玩密室的更多相关文章

  1. LUOGU P4253 [SCOI2015]小凸玩密室(树形dp)

    传送门 解题思路 玄学树形\(dp\),题目描述极其混乱...看错了两次题,设首先根据每次必须点完子树里的灯才能点别的,那么点灯情况只有两种,第一种是点到某一个祖先,第二种是点到某一个祖先的兄弟.所以 ...

  2. [BZOJ4446]SCoi2015 小凸玩密室 树形DP(烧脑高能预警)

    4446: [Scoi2015]小凸玩密室 Time Limit: 10 Sec  Memory Limit: 128 MB Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点 ...

  3. bzoj 4446: [Scoi2015]小凸玩密室

    Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯 泡即可逃出密室.每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要 ...

  4. BZOJ4446:[SCOI2015]小凸玩密室(树形DP)

    Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室. 每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要 ...

  5. BZOJ4446 [Scoi2015]小凸玩密室 【树形Dp】

    题目 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯 泡即可逃出密室.每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要花费,之后每点亮4 ...

  6. [bzoj4446] [loj#2009] [Scoi2015] 小凸玩密室

    Description 小凸和小方相约玩密室逃脱,这个密室是一棵有 \(n\) 个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室.每个灯泡有个权值 \(Ai\) ,每条边也有个权值 \ ...

  7. BZOJ4446: [Scoi2015]小凸玩密室

    用ui,j表示走完i的子树后走到i的深度为j的祖先的兄弟的最小代价: 用vi,j表示走完i的子树后走到i的深度为j的祖先的最小代价,用u算出v. 枚举起点,计算答案. #include<bits ...

  8. 2019.03.26 bzoj4446: [Scoi2015]小凸玩密室(树形dp)

    传送门 题意简述: 给一棵完全二叉树,有点权aia_iai​和边权,每个点有一盏灯,现在要按一定要求点亮: 任意时刻点亮的灯泡必须连通 点亮一个灯泡后必须先点亮其子树 费用计算如下:点第一盏灯不要花费 ...

  9. BZOJ.4446.[SCOI2015]小凸玩密室(树形DP)

    BZOJ LOJ 洛谷 (下面点亮一个灯泡就说成染色了,感觉染色比较顺口... 注意完全二叉树\(\neq\)满二叉树,点亮第一个灯泡\(\neq\)第一次点亮一号灯泡,根节点应该就是\(1\)... ...

  10. BZOJ4446 SCOI2015小凸玩密室(树形dp)

    设f[i][j]为由根进入遍历完i子树,最后一个到达的点是j时的最小代价,g[i][j]为由子树内任意一点开始遍历完i子树,最后一个到达的点是j时的最小代价,因为是一棵完全二叉树,状态数量是nlogn ...

随机推荐

  1. 如何将png转为svg

    如何将png转为svg如图所示. 工具/原料 Inkscape 方法/步骤 1 打开Inkscape,"文件-打开"如图. 2  打开你需要转化的png图片.如图所示. 3 打开你 ...

  2. 在VS Code中使用Snippet Craft扩展提高编码效率

    Snippet Craft 一个VS Code代码片段管理插件 功能 创建和插入代码片段 在编辑器区域右键菜单中点击插入Snippet,或在代码片段视图中点击条目,则会将代码片段插入到当前激活文档的光 ...

  3. 使用 Gradle 构建包含所有依赖的 JAR 包

    在 Gradle 中构建一个包含所有依赖的 jar 包(通常被称为"fat jar"或者"uber jar"),你可以使用 shadowJar 插件来包含编译的 ...

  4. 使用广播星历计算卫星坐标(Python)

    前言 本代码为GNSS课程设计代码,仅供参考,使用的计算方法与公式均来源于王坚主编的<卫星定位原理与应用(第二版)>. 本代码计算结果可以通过下载精密星历进行比照,误差在1-10m左右. ...

  5. Coursera, Big Data 5, Graph Analytics for Big Data, Week 4

    Graph Analytics With Neo4j 讲了怎样用Cypher 脚本语言去操作 Neo4j, 包括加graph, 导入csv数据. 接着讲了一些neo4j 的基本操作. 最后讲的,pat ...

  6. 小tips:nodejs请求接口超时使用中间件connect-timeout实现自动超时机制

    如果在请求中不设置超时时间,那么一直处理loading卡屏状态,使用connect-timeout来设置自动超时时间. 安装: npm install connect-timeout -S 如下例子: ...

  7. ChatGPT论文降重Prompt

    你是一个已经阅读过大量论文的论文写作专家.我正在设计一个基于xxx系统.接下来,我将给你一个论文段落,你可以使用调整句子用词.句子结构等方法,重新描述这段话,对文章的内容进行润色,使之更加接近论文的写 ...

  8. Android Qcom USB Driver学习(六)

    眼图基础知识与详解 10分钟教会你看眼图 USB2.0 HUB眼图调试经验总结 一篇文章教你如何全面了解眼图测试! 预加重与去加重对眼图的影响 关于 USB 通信阻抗匹配的问题 硬件调试--眼图几个经 ...

  9. 2021年1月国产数据库排行榜:OceanBase重回前三,TDSQL增长趋势最强劲!

    墨天轮国产数据库排行榜新年第一期已发布.2021年1月份排行榜前三甲依次为 TiDB .DaMeng.OceanBase .PingCAP TiDB 稳居冠军的宝座,短时间内难以撼动,开源的商业数据库 ...

  10. 共124篇!墨天轮“高可用架构”干货文档分享(含Oracle、MySQL、PG)

    大家期待的高可用篇来啦!在上期<墨天轮高分技术文档分享-Oracle升级迁移篇>中大家对数据库高可用架构相关文档呼声较高,这不就来啦! 数据库的高可用架构能够在发生宕机或意外中断等故障时起 ...