【NOI2009】二叉查找树

【问题描述】

  已知一棵特殊的二叉查找树。根据定义,该二叉查找树中每个结点的数据值
都比它左子树结点的数据值大,而比它右子树结点的数据值小。
另一方面,这棵查找树中每个结点都有一个权值,每个结点的权值都比它的
儿子结点的权值要小。
已知树中所有结点的数据值各不相同;所有结点的权值也各不相同。这时可
得出这样一个有趣的结论:如果能够确定树中每个结点的数据值和权值,那么树
的形态便可以唯一确定。因为这样的一棵树可以看成是按照权值从小到大顺序插
入结点所得到的、按照数据值排序的二叉查找树。
一个结点在树中的深度定义为它到树根的距离加 1。因此树的根结点的深度
为 1。
  每个结点除了数据值和权值以外,还有一个访问频度。我们定义一个结点在
树中的访问代价为它的访问频度乘以它在树中的深度。整棵树的访问代价定义为
所有结点在树中的访问代价之和。
  现在给定每个结点的数据值、 权值和访问频度, 你可以根据需要修改某些
结点的权值,但每次修改你会付出 K 的额外修改代价。你可以把结点的权值改
为任何实数,但是修改后所有结点的权值必须仍保持互不相同。现在你要解决的
问题是, 整棵树的访问代价与额外修改代价的和最小是多少?
【输入格式】
输入文件为 treapmod.in。
输入文件第一行包含两个正整数 N 和 K。 N 为结点的个数, K 为每次
修改所需的额外修改代价。
接下来一行包含 N 个非负整数,是每个结点的数据值。
再接下来一行包含 N 个非负整数,是每个结点的权值。
再接下来一行包含 N 个非负整数,是每个结点的访问频度。
所有的数据值、权值、访问频度均不超过 400000。每两个数之间都有一个
空格分隔,且行尾没有空格。
【输出格式】
输出文件为 treapmod.out。
输出文件只有一个数字,即你所能得到的整棵树的访问代价与额外修改代价
之和的最小值。
【样例 1 输入】
4 10
1 2 3 4
1 2 3 4
1 2 3 4
【样例 1 输出】
29
第 6 页 共 8 页
【样例 1 说明】
输入的原图是左图,它的访问代价是 1×1+2×2+3×3+4×4=30。最佳的修改方
案 是 把 输 入 中 的 第 3 个 结 点 的 权 值 改 成 0 , 得 到 右 图 ,
访 问 代 价 是 1×2+2×3+3×1+4×2=19,加上额外修改代价 10,一共是 29。
【子任务】
40%的数据满足 N ≤ 30;
70%的数据满足 N ≤ 50;
100%的数据满足 N ≤ 70, 1 ≤ K ≤ 30000000。

【题解】

  数据值已经确定了,那么这棵树的中序遍历就已经确定了,我们相当于改变权值来改变深度。

  而权值可以是任意实数,但是却和答案无关,我们完全可以离散化一下。

  那么我们设dp[i][j][w]表示以区间[i,j]内的节点为树,根节点都>=w的方案总数。

  我们通过枚举区间内的根k,可以写出转移方程(sum(i,j)表示[i,j]的访问频率和)。

  当k>=w时,我们就可以把k之间弄成根,dp[i][j][w]=min(dp[i][k-1][wk]+dp[k+1][j][wk]+sum(i,j));

  也可以把k的权值修改成w,dp[i][j][w]=min(dp[i][k-1][w]+dp[k+1][w]+K+sum(i,j));

  因为如果直接dp偏序关系不太明确,在实现时可以使用记忆化搜索。(表示一开始直接dp调了一个上午没调出来)

【Code】

  

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
#define REP(i,a,b) for(register int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(register int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(register int i=start[(a)];i;i=e[i].next)
inline int read()
{
int sum=,p=;char ch=getchar();
while(!((''<=ch && ch<='') || ch=='-'))ch=getchar();
if(ch=='-')p=-,ch=getchar();
while(''<=ch && ch<='')sum=sum*+ch-,ch=getchar();
return sum*p;
} const int maxn=; int n,K; struct node {
int a,b,c;
};
node g[maxn]; bool cmp (const node x,const node y)
{
return x.a<y.a;
} int Sum(int x,int y)
{
return g[y].c-g[x-].c;
} void init()
{
int s[maxn];
n=read();K=read();
REP(i,,n)g[i].a=read();
REP(i,,n)g[i].b=read(),s[i]=g[i].b;
REP(i,,n)g[i].c=read();
sort(g+,g+n+,cmp);
sort(s+,s+n+);
int cnt=unique(s+,s+n+)-(s+);
REP(i,,n)
{
REP(j,,cnt)
{
if(g[i].b==s[j]){g[i].b=j;break;}
}
}
REP(i,,n)g[i].c+=g[i-].c;
} ll dp[maxn][maxn][maxn]; void chkmin(ll &a,ll b)
{
if(a>b)a=b;
}
#define inf 0x7ffffffffff
ll dfs(int l,int r,int k)
{
if(l>r)return ;
if(~dp[l][r][k])return dp[l][r][k];
ll ans=inf;
REP(i,l,r)
{
chkmin(ans,dfs(l,i-,k)+dfs(i+,r,k)+K);
if(g[i].b>=k)chkmin(ans,dfs(l,i-,g[i].b)+dfs(i+,r,g[i].b));
}
return dp[l][r][k]=ans+Sum(l,r);
} void doing()
{
memset(dp,-,sizeof(dp));
//REP(i,1,n)dp[i][i][g[i].b]=Sum(i,i);
/*REP(len,1,n-1)
{
REP(i,1,n-len)
{
int j=i+len;
REP(k,1,Min(i,j))
{
REP(l,i,j)
{
int Mn=Min(i,j),z=0;
if(Mn==g[l].b)z=0;else z=K;
chkmin(dp[i][j][k],dp[i][l-1][Mn]+dp[l+1][j][Mn]+z+Sum(i,j));
}
}
}
}*/
cout<<dfs(,n,)<<endl;
}
int main()
{
init();
doing();
return ;
}

NOI2009 二叉查找树 【区间dp】的更多相关文章

  1. bzoj 1564 [NOI2009]二叉查找树 区间DP

    [NOI2009]二叉查找树 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 906  Solved: 630[Submit][Status][Discu ...

  2. 洛谷$P1864\ [NOI2009]$二叉查找树 区间$dp$

    正解:区间$dp$ 解题报告: 传送门$QwQ$ 首先根据二叉查找树的定义可知,数据确定了,这棵树的中序遍历就已经改变了,唯一能改变的就是通过改变权值从而改变结点的深度. 发现这里权值的值没有意义,所 ...

  3. [BZOJ1564][NOI2009]二叉查找树 树形dp 区间dp

    1564: [NOI2009]二叉查找树 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 879  Solved: 612[Submit][Status] ...

  4. BZOJ 1564: [NOI2009]二叉查找树( dp )

    树的中序遍历是唯一的. 按照数据值处理出中序遍历后, dp(l, r, v)表示[l, r]组成的树, 树的所有节点的权值≥v的最小代价(离散化权值). 枚举m为根(p表示访问频率): 修改m的权值 ...

  5. [洛谷P1864] NOI2009 二叉查找树

    问题描述 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结点的权值都比它的 ...

  6. P1864 [NOI2009]二叉查找树

    链接P1864 [NOI2009]二叉查找树 这题还是蛮难的--是我菜. 题目描述中的一大堆其实就是在描述\(treap.\),考虑\(treap\)的一些性质: 首先不管怎么转,中序遍历是确定的,所 ...

  7. 【BZOJ-4380】Myjnie 区间DP

    4380: [POI2015]Myjnie Time Limit: 40 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 162  Solved: ...

  8. 【POJ-1390】Blocks 区间DP

    Blocks Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5252   Accepted: 2165 Descriptio ...

  9. 区间DP LightOJ 1422 Halloween Costumes

    http://lightoj.com/volume_showproblem.php?problem=1422 做的第一道区间DP的题目,试水. 参考解题报告: http://www.cnblogs.c ...

  10. BZOJ1055: [HAOI2008]玩具取名[区间DP]

    1055: [HAOI2008]玩具取名 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1588  Solved: 925[Submit][Statu ...

随机推荐

  1. HTML 5 <embed> 标签

    定义和用法 <embed> 标签定义嵌入的内容,比如插件. 实例 <embed src="helloworld.swf" />

  2. Java泛型类和泛型方法

    java编程思想说道: 泛型类是应用在整个类上,但同时可以在类中包含参数化方法,而这个方法所在的类可以是泛型,也可以不是泛型,也就是说是否有泛型方法,与其所在的类是否是泛型类没有关系. 泛型方法是的该 ...

  3. Mybatis延迟加载和查询缓存

    摘录自:http://www.linuxidc.com/Linux/2016-07/133593.htm 阅读目录 一.延迟加载 二.查询缓存 一.延迟加载 resultMap可以实现高级映射(使用a ...

  4. jQuery的鼠标事件总结

    jQuery的鼠标事件总结 1.click()事件. 2.dbclick()鼠标双击事件 3.mousedown()鼠标按下事件 4.mouseup()鼠标松开事件 5.mouseover()从一个元 ...

  5. linux mysql下忘记root密码解决办法

    1 修改MySQL的登录设置 # vi /etc/my.cnf 在[mysqld]的中加上一句:skip-grant-tables  2 重新启动mysqld # /etc/init.d/mysqld ...

  6. SEO—Meta标签优化

    Meta标签之一"标题": 标题是网站中很重要的一个标签,他在搜索引擎中是直接显示出来的,一般情况下要网站的核心关键词和网站名称都写进去,这样更有利于网站的排名.但是要注意标题的长 ...

  7. 【转】sed & awk常用正则表达式

    正则表达式元字符 正则表达式中有两种基本元素: 以字面值或变量表示的值(如.代表任意单个字符). 操作符(如*代表将前面的字符重复任意次). 元字符汇总 特殊字符 用途 . 匹配除换行符以外的任意单个 ...

  8. Linux面试题(1)

    一.填空题: 1. 在Linux系统中,以 文件 方式访问设备 . 2. Linux内核引导时,从文件 /etc/fstab 中读取要加载的文件系统. 3. Linux文件系统中每个文件用 i节点 来 ...

  9. linux中的&&和||(linux中=和==效果是一样的)

    1. 命令1 && 命令2 命令1执行成功在执行命令2 2. 命令1 || 命令2 命令1执行失败后在执行命令2 我觉得这完全就是判断呀.

  10. Model和ModelAndView

    在请求处理方法可出现和返回的参数类型中,最重要的就是Model和ModelAndView.对于MVC框架,控制器Controller执行业务逻辑,用于产生模型数据Model,而试图View则用于渲染模 ...