4446: [Scoi2015]小凸玩密室

Time Limit: 10 Sec  Memory Limit: 128 MB

Description

小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡。点亮所有灯
泡即可逃出密室。每个灯泡有个权值Ai,每条边也有个权值bi。点亮第1个灯泡不需要花费,之后每点亮4
个(1个)新的灯泡V的花费,等于上一个被点亮的灯泡U到这个点V的距离Du,v,乘以这个点的权值Av。在点灯
的过程中,要保证任意时刻所有被点亮的灯泡必须连通,在点亮一个灯泡后必须先点亮其子树所有灯泡才能点亮其他灯泡。请告诉他们,逃出密室的最少花费是多少。

Input

第1行包含1个数n,代表节点的个数
第2行包含n个数,代表每个节点的权值ai。(i=l,2,…,n)
第3行包含n-l个数,代表每条边的权值bi,第i号边是由第(i+1)/2号点连向第i+l号点的边。
(i=l,2...N-1)

Output

输出包含1个数,代表最少的花费。

Sample Input

3
5 1 2
2 1

Sample Output

5

HINT

对于100%的数据,1≤N≤2×105,1<Ai,Bi≤10^5

(其实我是回来补暑假没写完的题解的)

题解:

(首先我经过激烈的思想斗争,认为那个点亮灯泡的花费计算只与上一个有关(其实是因为前4个太难考虑了...)

事实证明这样做是对的..就是只考虑上一个:(

有了之前做非线性DP的经验,我一开始想的还是合并类型

但是发现数据范围不太对....这似乎是一个介于O(n)和O(n2)范围内的DP

我们考虑怎么定义状态,以及怎么转移.

一开始我想的是f[i][j]表示"走完以i为根的子树之后走去j点的最小花费"

但是我发现这个MLE了,2e5开不下

但是这又是一颗完全二叉树,所以我们考虑能不能应用他的一些性质

我们观察到,点灯泡的起点没有确定,但是题目有这样的两个限制:

要保证任意时刻所有被点亮的灯泡必须连通.

在点亮一个灯泡后必须先点亮其子树所有灯泡才能点亮其他灯泡

这样的话,某一个点被点亮的时候只能有三种转移的情况:从儿子走来,从兄弟走来和从父亲走来(废话)

因此,当某一个子树被完全点亮之后,我们就要去某一个他的祖先,或者是他某个祖先的儿子

我们发现上面这两个都与这个节点的祖先有关(这里我们把自己也看成自己的祖先)

由于这是一棵二叉树,我们完全可以通过位运算(左移,右移和异或)来计算出某个节点的某个深度的祖先.

这样,第二维完全不用是O(n)的:我们可以把第二维设为深度,即走完以i为根的子树之后走去深度为j的祖先节点的“XXXX”的最小花费

那么我们再考虑一下:我们这个点的祖先节点可能已经被点亮,也可能没有被点亮。如果已经点亮,我们就必须去点亮祖先的兄弟那棵子树。

因此我们定义两个数组:

f(ather)[i][j]表示走完以i为根的子树之后去点亮深度为j的祖先节点的最小花费

b(rother)[i][j]表示走完以i为根的子树之后去点亮深度为j的祖先节点的兄弟节点的最小花费

接下来我们考虑状态的转移。最好想到的是节点i是叶子节点的情况:直接走去对应的节点即可。

我们再考虑下一种情况:只有一个儿子。那么此时我们必须先走到这个儿子,然后再从这个儿子走去对应的节点。
如果有2个儿子,我们应该考虑两种情况,即先去左儿子还是先去右儿子,然后取较小值,并累加中间的权值。
这样,转移部分就被我们解决了。具体代码实现就是上面这个思路的体现。
最后,我们再来考虑“第一个灯泡不确定”这个条件
假设第一步点亮了灯泡u,设它的兄弟为bro(ther),那么接下来我们应该一步一步往上爬,直到点亮所有灯泡。
也就是说重复u->fa->bro->fa->bro->......这个过程
我们只需要模拟这个过程,就可以得到第一步点亮u的最小花费(记得讨论bro不存在的情况)
然后在所有最小值里取最小即可。
这道题的思维含量很高,是一道不可多得的好题呀!

完整代码见下:

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=;
typedef long long LL;
int n,l[N],r[N],deep[N];
LL f[N][],b[N][],a[N],lval[N],rval[N],dis[N];
int main()
{
scanf("%d",&n);LL v;int rt;deep[]=;
for(int i=;i<=n;i++)scanf("%lld",&a[i]);
for(int i=;i<n;i++)
{
scanf("%lld",&v);
rt=(i+)>>,deep[i+]=deep[rt]+;
if((i+)&) r[rt]=i+,rval[rt]=v,dis[r[rt]]=dis[rt]+rval[rt];
else l[rt]=i+,lval[rt]=v,dis[l[rt]]=dis[rt]+lval[rt];
}
for(int i=n;i>;i--)
for(int j=;j<=deep[i];j++)
if(!r[i])
if(!l[i])
{
int fa=i>>(deep[i]-j+),fab=(i>>(deep[i]-j))^;
b[i][j]=( dis[i]+dis[fab]-(dis[fa]<<) )*a[fab];
}
else b[i][j]=lval[i]*a[l[i]]+b[l[i]][j];
else b[i][j]=min(lval[i]*a[l[i]]+b[l[i]][deep[i]+]+b[r[i]][j],rval[i]*a[r[i]]+b[r[i]][deep[i]+]+b[l[i]][j]);
for(int i=n;i;i--)
for(int j=;j<=deep[i];j++)
{
if(!r[i])
if(!l[i])
if(!j)f[i][j]=;
else
{
int fa=i>>(deep[i]-j);
f[i][j]=(dis[i]-dis[fa])*a[fa];
}
else f[i][j]=lval[i]*a[l[i]]+f[l[i]][j];
else f[i][j]=min(lval[i]*a[l[i]]+b[l[i]][deep[i]+]+f[r[i]][j],rval[i]*a[r[i]]+b[r[i]][deep[i]+]+f[l[i]][j]);
}
LL ans=f[][];
for(int i=;i<=n;i++)
{
int u=i,bro=u^;
LL tmp=f[u][deep[u]-];
while(u>)
{
if(bro>n)tmp+=a[u>>]*(dis[u>>]-dis[u>>]);
else tmp+=a[bro]*(dis[bro]-dis[u>>])+f[bro][deep[u>>]-];
u>>=,bro=u^;
}
ans=min(ans,tmp);
}
printf("%lld\n",ans);
}

[BZOJ4446]SCoi2015 小凸玩密室 树形DP(烧脑高能预警)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. Linux下的文件系统结构

    文章链接:https://blog.csdn.net/qq_38646470/article/details/80159630

  2. Jmeter中正则表达式提取器

    在使用Jmeter过程中,会经常使用到正则表达式提取器提取器,虽然并不直接涉及到请求的测试,但是对于数据的传递起着很大的作用,本篇博文就是主要讲解关于正则表达式及其在Jmeter的Sampler中的调 ...

  3. 零基础学python之入门和列表数据(附详细的代码解释和执行结果截图)

    Python学习笔记 1 快速入门 下载安装好Python之后,在开始找到 双击打开一个窗口,这是一个shell界面编辑窗口,点击左上角的file——new file新建一个窗口,这里可以输入完整的代 ...

  4. Oracle扩展包(pipe,alert,job,scheduler)

    --定义包中函数的纯度级别 create or replace package purityTest is type dept_typ is table of dept%rowtype index b ...

  5. windows c++如何使窗口动态改变位置

    在windows软件中,经常会碰到一个功能:鼠标hover在某个地方时会出现窗口,有时候这个窗口的位置是会动态调整的. 熟悉使用windows API,理解windows中虚拟坐标.工作区坐标.屏幕坐 ...

  6. 爬虫进阶教程:极验(GEETEST)验证码破解教程

    摘要 爬虫最大的敌人之一是什么?没错,验证码!Geetest作为提供验证码服务的行家,市场占有率还是蛮高的.遇到Geetest提供的滑动验证码怎么破?授人予鱼不如授人予渔,接下来就为大家呈现本教程的精 ...

  7. spring-session实现分布式集群session的共享(转)

    原文: https://www.cnblogs.com/youzhibing/p/7348337.html HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保 ...

  8. spring boot的maven项目报404错误

    $.ajax({ async: false, type: "POST", url:'searchFileSource', contentType : "applicati ...

  9. Task 4.2 求一个矩阵的最大子矩阵的和

    任务:输入一个二维整形数组,数组里有正数也有负数.二维数组中连续的一个子矩阵组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). (1)设计思想:把二维矩阵分解成 ...

  10. 团队作业之404 Note Found Team

    如果记忆是一个罐头的话,我希望这一罐罐头不会过期----<重庆森林> 404 Note Found Team 如果记忆是一个备忘录的话,别说了,它不会过期----<404 Note ...