BZOJ4446 SCOI2015小凸玩密室(树形dp)
设f[i][j]为由根进入遍历完i子树,最后一个到达的点是j时的最小代价,g[i][j]为由子树内任意一点开始遍历完i子树,最后一个到达的点是j时的最小代价,因为是一棵完全二叉树,状态数量是nlogn的。转移考虑四种走法:根→左子树→右子树;根→右子树→左子树;左子树→根→右子树;右子树→根→左子树 即可。好像和大多数题解不一样,明明感觉这种做法比较显然。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 200010
#define inf 100000000000000000ll
int n,a[N],p[N],deep[N],t;
vector<int> son[N];
vector<long long> f[N],g[N];
struct data{int to,nxt,len;
}edge[N];
void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
void dfs(int k)
{
int cnt=;
for (int i=p[k];i;i=edge[i].nxt)
{
cnt++;
deep[edge[i].to]=deep[k]+edge[i].len;
dfs(edge[i].to);
for (int j=;j<son[edge[i].to].size();j++)
son[k].push_back(son[edge[i].to][j]);
}
son[k].push_back(k);
if (cnt==) {f[k].push_back();g[k].push_back();return;}
if (cnt==)
{
long long v=inf;
for (int i=;i<son[k].size()-;i++)
f[k].push_back(f[edge[p[k]].to][i]+1ll*edge[p[k]].len*a[edge[p[k]].to]),
g[k].push_back(f[k][i]),v=min(v,f[edge[p[k]].to][i]+1ll*(deep[son[edge[p[k]].to][i]]-deep[k])*a[k]);
f[k].push_back(inf),g[k].push_back(v);
}
else
{
long long P=inf,Q=inf,X=inf,Y=inf;
int x=edge[p[k]].to,y=edge[edge[p[k]].nxt].to,w=edge[p[k]].len,v=edge[edge[p[k]].nxt].len;
for (int i=;i<son[x].size();i++)
P=min(P,f[x][i]+1ll*w*a[x]+1ll*(deep[son[x][i]]-deep[k])*a[y]),
X=min(X,g[x][i]+1ll*(deep[son[x][i]]-deep[k])*a[k]);
for (int i=;i<son[y].size();i++)
Q=min(Q,f[y][i]+1ll*v*a[y]+1ll*(deep[son[y][i]]-deep[k])*a[x]),
Y=min(Y,g[y][i]+1ll*(deep[son[y][i]]-deep[k])*a[k]);
X=min(X,P),Y=min(Y,Q);
for (int i=;i<son[x].size();i++)
f[k].push_back(Q+1ll*w*a[x]+f[x][i]),g[k].push_back(Y+1ll*w*a[x]+f[x][i]);
for (int i=;i<son[y].size();i++)
f[k].push_back(P+1ll*v*a[y]+f[y][i]),g[k].push_back(X+1ll*v*a[y]+f[y][i]);
f[k].push_back(inf),g[k].push_back(inf);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4446.in","r",stdin);
freopen("bzoj4446.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();
for (int i=;i<=n;i++) a[i]=read();
for (int i=;i<n;i++) addedge(i+>>,i+,read());
dfs();
long long ans=inf;
for (int i=;i<son[].size();i++) ans=min(ans,g[][i]);
cout<<ans;
return ;
}
BZOJ4446 SCOI2015小凸玩密室(树形dp)的更多相关文章
- [BZOJ4446]SCoi2015 小凸玩密室 树形DP(烧脑高能预警)
4446: [Scoi2015]小凸玩密室 Time Limit: 10 Sec Memory Limit: 128 MB Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点 ...
- BZOJ4446:[SCOI2015]小凸玩密室(树形DP)
Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室. 每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要 ...
- LUOGU P4253 [SCOI2015]小凸玩密室(树形dp)
传送门 解题思路 玄学树形\(dp\),题目描述极其混乱...看错了两次题,设首先根据每次必须点完子树里的灯才能点别的,那么点灯情况只有两种,第一种是点到某一个祖先,第二种是点到某一个祖先的兄弟.所以 ...
- BZOJ.4446.[SCOI2015]小凸玩密室(树形DP)
BZOJ LOJ 洛谷 (下面点亮一个灯泡就说成染色了,感觉染色比较顺口... 注意完全二叉树\(\neq\)满二叉树,点亮第一个灯泡\(\neq\)第一次点亮一号灯泡,根节点应该就是\(1\)... ...
- BZOJ4446 [Scoi2015]小凸玩密室 【树形Dp】
题目 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯 泡即可逃出密室.每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要花费,之后每点亮4 ...
- 2019.03.26 bzoj4446: [Scoi2015]小凸玩密室(树形dp)
传送门 题意简述: 给一棵完全二叉树,有点权aia_iai和边权,每个点有一盏灯,现在要按一定要求点亮: 任意时刻点亮的灯泡必须连通 点亮一个灯泡后必须先点亮其子树 费用计算如下:点第一盏灯不要花费 ...
- BZOJ4446: [Scoi2015]小凸玩密室
用ui,j表示走完i的子树后走到i的深度为j的祖先的兄弟的最小代价: 用vi,j表示走完i的子树后走到i的深度为j的祖先的最小代价,用u算出v. 枚举起点,计算答案. #include<bits ...
- [bzoj4446] [loj#2009] [Scoi2015] 小凸玩密室
Description 小凸和小方相约玩密室逃脱,这个密室是一棵有 \(n\) 个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室.每个灯泡有个权值 \(Ai\) ,每条边也有个权值 \ ...
- bzoj 4446: [Scoi2015]小凸玩密室
Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯 泡即可逃出密室.每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要 ...
随机推荐
- 来自一枚初生牛犊不怕虎的小菜鸟的Mock.js使用,不足之处欢迎读者的指出 谢谢
本文章写的是基于require的mock.js的几种常用生成随机数据和ajax模拟前后端的交互信息 <script src="./app/libs/require.js"&g ...
- wamp环境下安装imagick扩展
先上图,如下是安装成功后的phpinfo()界面: 安装步骤: 1.先确定安装版本,比如我的的php : php7.0.12 x86 ts 那么就需要三方版本 要一致:imagick软件本身( 如x ...
- RubyMine常用快捷键
一级必会 Shift+F10:运行running Ctrl+Alt+R:弹出RakeCtrl+Alt+G:弹出GenerateCtrl+Alt+L:格式化代码Alt+F1:切换视图(Project, ...
- Java学习笔记十:Java的数组以及操作数组
Java的数组以及操作数组 一:什么是数组: 数组可以理解为是一个巨大的“盒子”,里面可以按顺序存放多个类型相同的数据,比如可以定义 int 型的数组 scores 存储 4 名学生的成绩 数组中的元 ...
- python2.7入门---列表(List)
序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推.Python有6个序列的内置类型,但最常见的是列表和元组. ...
- python2.7入门---循环语句(for&嵌套循环)
咱们直接先来看for循环.Python for循环可以遍历任何序列的项目,如一个列表或者一个字符串.然后再来看一下它的语法结构: for iterating_var in sequence: ...
- LeetCode:24. Swap Nodes in Pairs(Medium)
1. 原题链接 https://leetcode.com/problems/swap-nodes-in-pairs/description/ 2. 题目要求 给定一个链表,交换相邻的两个结点.已经交换 ...
- Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. org/apache/hadoop/hbase/
Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. org/apache/hadoop/hbase/ ...
- Thymeleaf 常用th标签基础整理
(一)Thymeleaf 是个什么? 简单说, Thymeleaf 是一个跟 Velocity.FreeMarker 类似的模板引擎,它可以完全替代 JSP .相较与其他的模板引擎,它有如下 ...
- kill -9 vs killall
kill Linux中的kill命令用来终止指定的进程(terminate a process)的运行,是Linux下进程管理的常用命令.通常,终止一个前台进程可以使用Ctrl+C键,但是,对于一个后 ...