bzoj 1564 [NOI2009]二叉查找树

题目描述

已知一棵特殊的二叉查找树。根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小。

另一方面,这棵查找树中每个结点都有一个权值,每个结点的权值都比它的儿子结点的权值要小。

已知树中所有结点的数据值各不相同;所有结点的权值也各不相同。这时可得出这样一个有趣的结论:如果能够确定树中每个结点的数据值和权值,那么树的形态便可以唯一确定。因为这样的一棵树可以看成是按照权值从小到大顺序插入结点所得到的、按照数据值排序的二叉查找树。

一个结点在树中的深度定义为它到树根的距离加1。因此树的根结点的深度为1。

每个结点除了数据值和权值以外,还有一个访问频度。我们定义一个结点在树中的访问代价为它的访问频度乘以它在树中的深度。整棵树的访问代价定义为所有结点在树中的访问代价之和。

现在给定每个结点的数据值、权值和访问频度,你可以根据需要修改某些结点的权值,但每次修改你会付出K的额外修改代价。你可以把结点的权值改为任何实数,但是修改后所有结点的权值必须仍保持互不相同。现在你要解决的问题是,整棵树的访问代价与额外修改代价的和最小是多少?

输入输出格式

输入格式:

输入文件中的第一行为两个正整数N,K。其中:N表示结点的个数,K表示每次修改所需的额外修改代价。

接下来的一行为N个非负整数,表示每个结点的数据值。

再接下来的一行为N个非负整数,表示每个结点的权值。

再接下来的一行为N个非负整数,表示每个结点的访问频度。

其中:所有的数据值、权值、访问频度均不超过400000。每两个数之间都有一个空格分隔,且行尾没有空格。

输出格式:

输出文件中仅一行为一个数,即你所能得到的整棵树的访问代价与额外修改代价之和的最小值。

输入输出样例

输入样例#1:  复制
4 10
1 2 3 4
1 2 3 4
1 2 3 4
输出样例#1:  复制
29

说明

【样例说明】

输入的原图是左图,它的访问代价是: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(l, r, v)表示[l, r]组成的树, 树的所有节点的权值≥v的最小代价(离散化权值).

枚举m为根(p表示访问频率):

修改m的权值 : dp(l, r, v) = min( dp(l, m-1, v) + dp(m+1, r, v) + p(l~r) + K )

不修改(m原先权值≥v) : dp(l, r, v) = min( dp(l, m-1, Value(m)) + dp(m+1, r, Value(m)) + p(l~r) )

时间复杂度$O( N log N + N^4 ) $  

 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 #define rep(i,a,b) for(int i=a;i<=b;i++) 
 4 #define Rep(i,a,b) for(int i=a;i>=b;i--) 
 5 #define ms(i,a)    memset(a,i,sizeof(a)) 
 6 #define gc()       getchar() 
 7 #define ll         long long 
 8 template<class T>void read(T &x){
 9     x=0; char c=gc(); 
10     while (!isdigit(c)) c=gc();  
11     while (isdigit(c)) x=x*10+(c^48),c=gc();  
12 }
13 int const N=70+3;  
14 ll  const inf=1LL<<50;  
15 ll  dp[N][N][N];  
16 int n,k,sum[N],b[N];    
17 struct node{
18     int v,d,s; 
19     bool operator <(const node &rhs) const { return v<rhs.v;}   
20 }a[N];  
21 ll dfs(int l,int r,int x){
22     if(l>r) return 0; 
23     if(~dp[l][r][x]) return dp[l][r][x]; 
24     ll &ret=dp[l][r][x]=inf; 
25     ll t=sum[r]-sum[l-1]; 
26     rep(i,l,r){
27         ret=min(ret,dfs(l,i-1,x)+dfs(i+1,r,x)+t+k);  
28         if(a[i].d>=x) ret=min(ret,dfs(l,i-1,a[i].d+1)+dfs(i+1,r,a[i].d+1) +t); 
29     }
30     return ret;  
31 }
32 int main(){
33     read(n); read(k);  
34     rep(i,1,n) read(a[i].v); 
35     rep(i,1,n) read(a[i].d);  
36     rep(i,1,n) read(a[i].s); 
37     rep(i,1,n) b[i]=a[i].d;  
38     sort(b+1,b+n+1);  
39     rep(i,1,n) a[i].d=lower_bound(b+1,b+n+1,a[i].d)-b;  
40     sort(a+1,a+n+1);  
41     rep(i,1,n) sum[i]=sum[i-1]+a[i].s;  
42     ms(-1,dp);  
43     printf("%lld\n",dfs(1,n,1));    
44     return 0; 
45 }
46             
47     
View Code

猜你喜欢

转载自www.cnblogs.com/ZJXXCN/p/10621772.html