19/10/30模拟测试T2二叉搜索树(区间DP)

经过昨天一晚上的冥思苦想以及 对四边形不等式的研究,我终于将T2的正解打了出来。

先看题:
在这里插入图片描述
就是保证一棵树的中序遍历不变,让你构造一棵树,满足题意。

这道题可以用区间DP,令 f i , j f_{i,j} fi,j表示只考虑节点[ i , j ]的答案。
在[i,j]区间中枚举决策点(根节点)k,则有 f i , j = m i n ( f i , k − 1 , f k + 1 , j ) + ∑ x = i j s u m [ x ] f_{i,j}=min(f_{i,k-1},f_{k+1,j})+\sum_{x=i}^jsum[x] fi,j=min(fi,k1,fk+1,j)+x=ijsum[x],
其中sum[x]为节点[ i , j ]的权值之和,可以用预处理的 j 的前缀和减去 i 的前缀和得到。
这是O(n 2 ^2 2)的做法,可以得40分。

接下来我们就要用到四边形不等式优化(详情可在《算法竞赛进阶指南》上查找)
可以证明 f i , j f_{i,j} fi,j满足四边形不等式,则有k单调,所以我们只需在[ i ,j-1 ]与[ i+1 , j ]的决策点之间枚举即可。

下面贴代码:

#include<bits/stdc++.h> 
using namespace std;
#define in read()

int n,aa,p[5005][5005];
long long f[5005][5005],a[5005];

int in
{
	int i=0;char ch=0;
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) {i=i*10+ch-'0';ch=getchar();}
	return i;
}

int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=in;
	for(int i=1;i<=n;i++)
	{
		aa=in;
		a[i]=a[i-1]+aa;
	}
	for(int l=n;l>=1;l--)
		for(int r=l;r<=n;r++)
		{
			
			f[l][r]=a[r]-a[l-1];
			if(l==r) {p[l][r]=l;continue;}
			long long minn=1e15;
			for(int i=p[l][r-1];i<=p[l+1][r];i++)
			{
				if(f[l][i-1]+f[i+1][r]<minn)
					minn=f[l][i-1]+f[i+1][r],p[l][r]=i;
			}
			f[l][r]+=minn;
		}
	printf("%lld",f[1][n]);
	return 0;
}
拆分二叉搜索树(Splitting a Binary Search Tree)是一种常见的二叉搜索树操作,它可以将一个二叉搜索树按照某个值进行拆分,得到两个新的二叉搜索树。 具体来说,假设我们有一个二叉搜索树T和一个值v,拆分操作会返回两个新的二叉搜索树T1和T2,其中T1包含所有小于v的节点,T2包含所有大于等于v的节点。同时,T1和T2保留了原始二叉搜索树T的结构。 拆分操作的实现可以通过递归方式进行,具体步骤如下: 1. 如果T为空,则返回两个空树T1和T22. 如果T的根节点值小于v,则将T的左子树拆分为T1和T2,然后将T的根节点作为T1的根节点。 3. 如果T的根节点值大于等于v,则将T的右子树拆分为T1和T2,然后将T的根节点作为T2的根节点。 下面是一个示例代码,实现了拆分二叉搜索树的操作: ``` class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def splitBST(root: TreeNode, v: int) -> List[TreeNode]: if not root: return [None, None] if root.val <= v: res = splitBST(root.right, v) root.right = res[0] return [root, res[1]] else: res = splitBST(root.left, v) root.left = res[1] return [res[0], root] ``` 在这个示例代码中,我们首先判断根节点值与v的大小,并根据大小递归拆分左子树或右子树。在递归过程中,我们始终保持根节点的位置不变,并且将拆分后的左右子树连接到根节点的左右孩子上。最终,我们返回拆分后的两棵树。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值