P1864 [NOI2009] 二叉查找树 题解

发布时间 2023-10-12 19:25:13作者: xuantianhao

二叉查找树

首先该树的中序遍历是唯一可以确定的(直接按照数据值排序即可)。

然后,因为权值可以被修改成一切实数,故我们完全可以把权值离散化掉。

于是我们现在可以设置一个 DP 状态 \(f[l,r,lim]\) 表示:

区间 \([l,r]\) 中的所有东西构成了一棵子树,且树中最小权值不小于 \(lim\) 的最优方案。

然后就枚举根转移即可。转移的时候就可以看作是子树内所有东西被整体提高了一层,所以直接增加 \(sum[l,r]\)(意为区间 \([l,r]\) 中的所有数据值之和)即可。同时,如果有当前枚举的根的权值不小于 \(lim\),显然就可以不修改,但是两边儿子的权值就必须比它大;否则则必须修改,两边儿子的权值下限还是 \(lim\)(因为根的权值可以被修改成一个略大于 \(lim\) 的实数)。

则时间复杂度 \(O(n^4)\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF=0x3f3f3f3f;
const int N=110;
struct node{
    int v,w,c;
}a[N];
int n,m;
int sum[N],f[N][N][N];
int dfs(int l,int r,int lim){
    if(l>r) return 0;
    if(f[l][r][lim]!=-1) return f[l][r][lim];
    int &now=f[l][r][lim];
	now=INF;
    for(int i=l;i<=r;i++){
        if(a[i].w>=lim) now=min(now,dfs(l,i-1,a[i].w)+dfs(i+1,r,a[i].w)+sum[r]-sum[l-1]);
        now=min(now,dfs(l,i-1,lim)+dfs(i+1,r,lim)+m+sum[r]-sum[l-1]);
    }
    return now;
}
bool cmp1(node x,node y){return x.w<y.w;}
bool cmp2(node x,node y){return x.v<y.v;}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
    cin>>n>>m;
	memset(f,-1,sizeof(f));
    for(int i=1;i<=n;i++) cin>>a[i].v;
    for(int i=1;i<=n;i++) cin>>a[i].w;
    for(int i=1;i<=n;i++) cin>>a[i].c;
    sort(a+1,a+n+1,cmp1);
    for(int i=1;i<=n;i++) a[i].w=i;
    sort(a+1,a+n+1,cmp2);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].c;
    cout<<dfs(1,n,1);
    return 0;
}