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

1564: [NOI2009]二叉查找树

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 879  Solved: 612
[Submit][Status][Discuss]

Description

Input

Output

只有一个数字,即你所能得到的整棵树的访问代价与额外修改代价之和的最小值。

Sample Input

4 10
1 2 3 4
1 2 3 4
1 2 3 4

Sample Output

29

HINT

输入的原图是左图,它的访问代价是1×1+2×2+3×3+4×4=30。最佳的修改方案是把输入中的第3个结点的权值改成0,得到右图,访问代价是1×2+2×3+3×1+4×2=19,加上额外修改代价10,一共是29。

Source

 

观察到这就是一个treap。(其实没什么卵用)

设sum为访问频率的前缀和。

考虑dp,设f[w][i][j]表示从i到j组成根节点为原权值第w小之后的点的最小总代价。

第一位从原来权值最大的点开始枚举w。

之后两维枚举i,j。

下一维枚举分割点d。

分两种情况讨论:

1.若修改点d的权值,那么f[w][i][j]=min(f[w][i][j],f[w][i][d-1]+f[w][d+1][to]+sum[to]-sum[i-1]+k);

2.若不修改点d的权值,那么点d的权值要大于m,f[w][i][j]=min(f[w][i][j],f[t[d].a][i][d-1]+f[t[d].a][d+1][to]+sum[to]-sum[i-1]);

ans=f[1][1][n]

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define maxn 80
 8 using namespace std;
 9 int read() {
10     int x=0,f=1;char ch=getchar();
11     for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
12     for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
13     return x*f;
14 }
15 int n,k;
16 struct data {
17     int v,a,p;
18 }t[maxn];
19 bool cmp1(data t1,data t2) {return t1.a<t2.a;}
20 bool cmp2(data t1,data t2) {return t1.v<t2.v;}
21 int sum[maxn];
22 int f[maxn][maxn][maxn];
23 int main() {
24     n=read();k=read();
25     for(int i=1;i<=n;i++) t[i].v=read();
26     for(int i=1;i<=n;i++) t[i].a=read();
27     for(int i=1;i<=n;i++) t[i].p=read();
28     sort(t+1,t+n+1,cmp1);
29     for(int i=1;i<=n;i++) t[i].a=i;
30     sort(t+1,t+n+1,cmp2);
31     for(int i=1;i<=n;i++) sum[i]=sum[i-1]+t[i].p;
32     for(int i=1;i<=n;i++)
33         for(int j=1;j<=n;j++)
34             if(t[i].a>=j) f[j][i][i]=t[i].p;
35             else f[j][i][i]=t[i].p+k;
36     for(int w=n;w>=1;w--) {
37         for(int j=1;j<=n;j++) {
38             for(int i=1;i+j<=n;i++) {
39                 int to=i+j;
40                 int tmp=2147483647;
41                 for(int d=i;d<=to;d++) {
42                     if(t[d].a>=w) tmp=min(tmp,f[t[d].a][i][d-1]+f[t[d].a][d+1][to]+sum[to]-sum[i-1]);
43                     tmp=min(tmp,f[w][i][d-1]+f[w][d+1][to]+sum[to]-sum[i-1]+k);
44                 }
45                 f[w][i][to]=tmp;
46             }
47         }
48     }
49     printf("%d",f[1][1][n]);
50 }
View Code

 

posted @ 2017-12-18 16:37  wls001  阅读(136)  评论(0编辑  收藏  举报