【BZOJ1564】【NOI2009】二叉查找树(动态规划)
【BZOJ1564】【NOI2009】二叉查找树(动态规划)
题面
已知一棵特殊的二叉查找树。根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小。
另一方面,这棵查找树中每个结点都有一个权值,每个结点的权值都比它的儿子结点的权值要小。
已知树中所有结点的数据值各不相同;所有结点的权值也各不相同。这时可得出这样一个有趣的结论:如果能够确定树中每个结点的数据值和权值,那么树的形态便可以唯一确定。因为这样的一棵树可以看成是按照权值从小到大顺序插入结点所得到的、按照数据值排序的二叉查找树。
一个结点在树中的深度定义为它到树根的距离加1。因此树的根结点的深度为1。
每个结点除了数据值和权值以外,还有一个访问频度。我们定义一个结点在树中的访问代价为它的访问频度乘以它在树中的深度。整棵树的访问代价定义为所有结点在树中的访问代价之和。
现在给定每个结点的数据值、权值和访问频度,你可以根据需要修改某些结点的权值,但每次修改你会付出K的额外修改代价。你可以把结点的权值改为任何实数,但是修改后所有结点的权值必须仍保持互不相同。现在你要解决的问题是,整棵树的访问代价与额外修改代价的和最小是多少?
输入输出格式
输入格式:
输入文件中的第一行为两个正整数N,K。其中:N表示结点的个数,K表示每次修改所需的额外修改代价。
接下来的一行为N个非负整数,表示每个结点的数据值。
再接下来的一行为N个非负整数,表示每个结点的权值。
再接下来的一行为N个非负整数,表示每个结点的访问频度。
其中:所有的数据值、权值、访问频度均不超过400000。每两个数之间都有一个空格分隔,且行尾没有空格。
输出格式:
输出文件中仅一行为一个数,即你所能得到的整棵树的访问代价与额外修改代价之和的最小值。
题解
我们知道,二叉查找树在拍平(也就是中序遍历)之后得到的序列是有序的
所以一般这类问题就可以考虑区间\(dp\)了。
因此,我们的第一想法设\(f[i][j]\)表示把\(i..j\)这一段构好树得到的最小代价。
首先我们不考虑权值的情况。
那么转移的时候,枚举一下树根,左右侧分别构树,作为当前根节点的儿子
同时所有点的深度都会加一,再额外计算一下这个值就可以了。
现在权值是可以修改的,如果自己想想,发现这棵二叉查找树是一个\(Treap\)
同时对于权值维护的是一个小根堆。另外,权值的大小没有意义,可以直接离散。
因此,在枚举根节点的时候,左右儿子对于当前根节点的影响一定是这段区间内权值的最小值所带来的影响。
所以,给状态加一维,设\(f[i][j][k]\)表示当前区间是\(i..j\),其中最小权值是\(k\)的二叉搜索树的最小代价。
考虑如何转移
对于区间,显然要先枚举当前的根节点,那么根节点一定就是最小权值,所以还枚举根节点的权值。
枚举左右子树的根节点的权值,这个权值一定要大于当前根节点的权值。
额外的费用只有是否修改当前根节点的权值。
所以,转移就是
\(f[i][j][k]=min(f[i][p-1][n]+f[p+1][j][m]+\sum_{l\in[i,j]}s[l]+[v[i]==k]·K)\)
这样复杂度是\(O(N^6)\)的(因为还要枚举左右子树的根节点的权值)
但是如果我们把状态的\(k\)改为所有值都不小于\(k\)的最小代价
这样就没有问题啦。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 75
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Node{int v,key,s;}t[MAX];
bool operator<(Node a,Node b){return a.v<b.v;}
int S[MAX],n,K;
int f[MAX][MAX][MAX];
int main()
{
n=read();K=read();
for(int i=1;i<=n;++i)t[i].v=read();
for(int i=1;i<=n;++i)S[i]=t[i].key=read();
for(int i=1;i<=n;++i)t[i].s=read();
sort(&S[1],&S[n+1]);int len=unique(&S[1],&S[n+1])-S-1;
for(int i=1;i<=n;++i)t[i].key=lower_bound(&S[1],&S[len+1],t[i].key)-S;
sort(&t[1],&t[n+1]);
for(int i=1;i<=n;++i)S[i]=t[i].s+S[i-1];
memset(f,63,sizeof(f));
for(int i=1;i<=n+1;++i)
for(int j=0;j<=n;++j)
f[i][i-1][j]=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
f[i][i][j]=t[i].s+(t[i].key!=j)*K;
for(int k=n;k;--k)
for(int l=1;l<=n;++l)
for(int i=1,j=i+l-1;j<=n;++i,++j)
for(int p=i;p<=j;++p)
{
f[i][j][k]=min(f[i][j][k],f[i][p-1][k]+f[p+1][j][k]+S[j]-S[i-1]+K);
if(k<=t[p].key)f[i][j][k]=min(f[i][j][k],f[i][p-1][t[p].key]+f[p+1][j][t[p].key]+S[j]-S[i-1]);
}
printf("%d\n",f[1][n][1]);
return 0;
}
【BZOJ1564】【NOI2009】二叉查找树(动态规划)的更多相关文章
- [BZOJ1564][NOI2009]二叉查找树 树形dp 区间dp
1564: [NOI2009]二叉查找树 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 879 Solved: 612[Submit][Status] ...
- BZOJ1564 NOI2009二叉查找树(区间dp)
首先按数据值排序,那么连续一段区间的dfs序一定也是连续的. 将权值离散化,设f[i][j][k]为i到j区间内所有点的权值都>=k的最小代价,转移时枚举根考虑是否修改权值即可. #includ ...
- [BZOJ1564][NOI2009]二叉查找树(区间DP)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1564 分析: 首先因为每个点的数据值不变,所以无论树的形态如何变,树的中序遍历肯定不变 ...
- bzoj1564: [NOI2009]二叉查找树
dp. 首先这棵树是一个treap. 权值我们可以改成任意实数,所以权值只表示相互之间的大小关系,可以离散化. 树的中序遍历是肯定确定的. 用f[l][r][w]表示中序遍历为l到r,根的权值必须大于 ...
- BZOJ 1564: [NOI2009]二叉查找树( dp )
树的中序遍历是唯一的. 按照数据值处理出中序遍历后, dp(l, r, v)表示[l, r]组成的树, 树的所有节点的权值≥v的最小代价(离散化权值). 枚举m为根(p表示访问频率): 修改m的权值 ...
- bzoj 1564 [NOI2009]二叉查找树 区间DP
[NOI2009]二叉查找树 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 906 Solved: 630[Submit][Status][Discu ...
- P1864 [NOI2009]二叉查找树
链接P1864 [NOI2009]二叉查找树 这题还是蛮难的--是我菜. 题目描述中的一大堆其实就是在描述\(treap.\),考虑\(treap\)的一些性质: 首先不管怎么转,中序遍历是确定的,所 ...
- NOI2009 二叉查找树 【区间dp】
[NOI2009]二叉查找树 [问题描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左子树结点的数据值大,而比它右子树结点的数据值小.另一方面,这棵查找树中每个结点都有 ...
- BZOJ 1564 :[NOI2009]二叉查找树(树型DP)
二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结 ...
- [洛谷P1864] NOI2009 二叉查找树
问题描述 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结点的权值都比它的 ...
随机推荐
- MapReduce编程中常用的字符操作
本文主要用于记录自己在编写mapreduce程序时常用的一些方法,后期会不断更新,用于自己复习和给新手一些帮助. 字符串操作 String str = " 12345"; // 字 ...
- LaTeX-手动安装宏包(package)以及生成帮助文档的整套流程
我使用的是ctex套装,本来已经自带了许多package,但是有时候还是需要使用一些没有预装的宏包,这时就需要自己安装package了.下载package可以从CTAN(Comprehensive T ...
- vue记录
vue项目中使用默认图片代替异常图片 第一种方法 <img onerror="javascript:this.src='../../static/custom.png';" ...
- vbox安装 ubuntu server 后 安装增强包
用vbox安装虚拟机系统如果不装增强包, 有很多东西就有点不好用-用vbox安装ubuntu server时,点击菜单中的安装增强功能.因为ubuntu server版本没有ui,所以不能很方便滴找到 ...
- Excel 移动列操作
- luogu P4135 作诗
嘟嘟嘟 郑重声明:我的前几到分块题写法上都有点小毛病,以这篇为主! 这道题感觉也是分块的基本套路,只不过卡常,得开氧气. 维护俩:sum[i][j]表示前 i 块中,数字 j 出现了多少次,ans[i ...
- Yii2.0 请求
1.获取请求参数 $request = Yii::$app->request; $get = $request->get(); // 等价于:$get = $_GET; $id = $re ...
- 学会WCF之试错法——超时
服务契约 [ServiceContract] public interface IService { [OperationContract] string GetData(int value); [O ...
- 使用jQuery实现伪分页
在之前的项目中遇到一个这样的问题,页面分为上下两部分(分别称为未选中设备信息部分和选中设备信息部分),上面是从数据库拿出来的所有的设备信息,下面是显式已选中的设备信息,页面如下所示: 可以选中其中的任 ...
- 在eclipse中查看HttpServlet源码失败的解决方法
在初次建立java EE 项目时,想要查看HttpServlet源码时会提示失败, 按照网上的方式,将Tomcat中lib中的servlet-api.jar的包导进去,发现并不管用.并且提示里面并不包 ...