博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ4446:[SCOI2015]小凸玩密室(树形DP)
阅读量:6245 次
发布时间:2019-06-22

本文共 2459 字,大约阅读时间需要 8 分钟。

Description

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

Input

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

Output

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

Sample Input

3
5 1 2
2 1

Sample Output

5

HINT

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

Solution

神仙树形DP

一条合法的行走路径,一定是先走完一个点的子树,再访问它的兄弟的子树,访问完了就回到父节点。以此类推。

也就是说要求从某个点出发,访问完其子树后回到某个祖先的最小代价。

设$f[x][i]$表示从$x$开始访问完$x$的子树后再走到深度为$i$的祖先(设为$kfa$)的最小代价。

设$g[x][i]$表示从$x$开始访问完$x$的子树后再走到深度为$i$的祖先的另外一个儿子的最小代价。

$DP$完了之后枚举最开始先点亮哪个灯然后统计答案。因为是完全二叉树所以时空都是$nlogn$

转移见代码,手画个图对比着理解效果应该会好一点……

Code

1 #include
2 #include
3 #define N (200009) 4 #define LL long long 5 #define ls (i<<1) 6 #define rs (i<<1|1) 7 #define kfa (i>>Depth[i]-j) 8 using namespace std; 9 10 LL n,Depth[N],Dist[N],a[N],b[N],g[N][21],f[N][21],ans=1e18;11 12 void DP()13 {14 for (int i=n; i>=1; --i)15 for (int j=0; j<=Depth[i]; ++j)16 if (ls>n)//当前是叶子 17 {18 f[i][j]=(Dist[i]-Dist[kfa])*a[kfa];19 g[i][j]=(Dist[i]-Dist[kfa]+b[kfa]+b[kfa^1])*a[kfa^1];20 }21 else if (ls==n)//只有左儿子22 {23 f[i][j]=b[ls]*a[ls]+f[ls][j];24 g[i][j]=b[ls]*a[ls]+g[ls][j];25 }26 else//左右儿子都有 27 {28 f[i][j]=min(29 b[ls]*a[ls]+g[ls][Depth[ls]]+f[rs][j],30 b[rs]*a[rs]+g[rs][Depth[rs]]+f[ls][j]);31 g[i][j]=min(32 b[ls]*a[ls]+g[ls][Depth[ls]]+g[rs][j],33 b[rs]*a[rs]+g[rs][Depth[rs]]+g[ls][j]);34 }35 }36 37 int main()38 {39 scanf("%lld",&n);40 for (int i=1; i<=n; ++i)41 scanf("%lld",&a[i]);42 for (int i=2; i<=n; ++i)43 scanf("%lld",&b[i]);44 for (int i=1; i<=n; ++i)45 {46 Depth[i]=Depth[i>>1]+1;47 Dist[i]=Dist[i>>1]+b[i];48 }49 DP(); 50 for (int i=1; i<=n; ++i)//枚举最先点哪个灯统计答案 51 {52 LL now=f[i][Depth[i]-1];53 for (int j=i; j!=1; j>>=1)54 if ((j^1)>n) now+=b[j>>1]*a[j>>2];55 else now+=b[j^1]*a[j^1]+f[j^1][Depth[j]-2];56 ans=min(ans,now);57 }58 printf("%lld\n",ans);59 }

转载于:https://www.cnblogs.com/refun/p/9890084.html

你可能感兴趣的文章
Open××× 分配固定IP
查看>>
elk+redis centos6.6安装与配置
查看>>
linux下svn命令大全
查看>>
windows server 2008 在vm上安装
查看>>
我的友情链接
查看>>
谷果等手机刷机build.prop解析
查看>>
Vbox虚拟机下 Linux网络配置
查看>>
Vmware vsphere知识中易混淆和忽略的多个概念
查看>>
Android客户端和服务端如何使用Token和Session
查看>>
Python Pycharm导入第三方包
查看>>
Nginx源码安装
查看>>
我的友情链接
查看>>
提升方法---提升方法AdaBoost方法
查看>>
Java语言的流程控制
查看>>
打乱数组(在其全排列中任选一个)Shuffle an Array
查看>>
红帆iOffice HD上线14天,Store排行榜第27位,商业类NO.1.
查看>>
我的友情链接
查看>>
nginx+django+uwsgi部署配置
查看>>
关于HWM的一些测试
查看>>
我的友情链接
查看>>