二叉搜索树TREE(线段树,区间DP)
前言
线段树+区间DP题,线段树却不是优化DP的,是不是很意外?
题面
二叉搜索树是一种二叉树,每个节点都有一个权值,并且一个点的权值比其左子树里的点权值都大,比起右子树里的点权值都小。
一种朴素的向二叉搜索树中插入节点的算法是,将新节点作为一个新的叶子节点插入树中,维持二叉搜索树的性质,并且不移动原有的节点。
现在有一个长度为
n
n
n 的排列
a
a
a,你可以任意重排第
l
l
l 到第
r
r
r 个数,但不移动其余数。接下来依次从
1
1
1 到
n
n
n 将
a
i
a_i
ai 作为新节点的权值插入一棵本来为空的二叉搜索树。试问得到的二叉搜索树所有节点的深度和最小是多少?(假定根节点的深度为
1
1
1)。
输入
第一行一个数
n
n
n ,(
1
≤
n
≤
1
0
5
1\leq n\leq 10^5
1≤n≤105)。
接下来一行一个排列
a
a
a 。
最后一行两个数
l
l
l,
r
r
r,(
1
≤
r
−
l
+
1
≤
200
1\leq r-l+1\leq 200
1≤r−l+1≤200)。
输出
一行一个答案。
题解
所有节点的深度和,等于所有子树大小之和。这样想
l
∼
r
l\sim r
l∼r 以内的变动就不会影响
r
r
r 后面的点了。
我们再分析往二叉搜索树中添加节点的过程,新点要成为叶子,并且在原数列的正确位置。假设当前数
x
x
x 的前一个数为
L
L
L ,后一个为
R
R
R ,我们会发现
L
+
1
∼
R
−
1
L+1\sim R-1
L+1∼R−1 以内的数都一定在
x
x
x 的子树中了,而且只有这些数在
x
x
x 的子树中。后者很好理解,前者是因为,该范围内除了
x
x
x 以外的数都比
x
x
x 晚成为叶子,因此若成为了
L
L
L 或
R
R
R 的后代便会矛盾。
所以,加点操作可以转化为:在一个数轴对应位置上加一个点,记前一个点位置为
L
L
L ,后一个点位置为
R
R
R ,对答案贡献
R
−
L
−
1
R-L-1
R−L−1 ,维护前后位置是经典的线段树操作了,当然也可以直接用 set ,快捷得多。
我们考虑
1
∼
R
1\sim R
1∼R 加完后的序列,如果
L
∼
R
L\sim R
L∼R 的点此时两两不相邻,那我们就没得变了,答案都是确定的了,因为每个点的贡献都取决于
1
∼
L
−
1
1\sim L-1
1∼L−1 的点了。但是,如果存在相邻的一段(
L
∼
R
L\sim R
L∼R 的点),我们就有的选了,可以通过安排这些点的加入顺序来改变贡献。假设有相邻的一段
m
m
m 个点,分割出
m
+
1
m+1
m+1 个线段,我们的操作就是每次把相邻的两条线段合并成一条线段,并算上这条线段的长度作为贡献,直到最后只有一条线段。
是不是很像合并果子?但是不一样,我们只能对相邻的果子进行操作。于是只能用区间 DP,这就是数据范围
r
−
l
+
1
≤
200
r-l+1\leq200
r−l+1≤200 的作用,时间复杂度
O
(
l
e
n
g
t
h
3
)
O({\rm length}^3)
O(length3) 能过。我们需要对形成的每段连续点分别进行区间 DP 。
总时间复杂度
O
(
n
log
n
+
(
r
−
l
+
1
)
3
)
O(n\log n+(r-l+1)^3)
O(nlogn+(r−l+1)3) 。
CODE
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define SI(x) multiset<x>::iterator
#define MI map<int,int>::iterator
#define eps (1e-4)
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f*x;
}
void putpos(LL x) {
if(!x) return ;
putpos(x/10); putchar('0'+(x%10));
}
void putnum(LL x) {
if(!x) putchar('0');
else if(x < 0) putchar('-'),putpos(-x);
else putpos(x);
}
void AIput(LL x,char c) {putnum(x);putchar(c);}
int n,m,s,o,k;
int L,R;
struct it{
int l,r;it(){l=0x3f3f3f3f,r=-1;}
it(int L,int R){l=L;r=R;}
}tre[MAXN<<2];
it merg(it a,it b) {return it(min(a.l,b.l),max(a.r,b.r));}
int M;
void maketree(int n) {
M=1;while(M<n+2) M<<=1;
for(int i = M+1;i <= M+n;i ++) tre[i] = it(n+1,0);
for(int i = M-1;i > 0;i --) tre[i] = merg(tre[i<<1],tre[i<<1|1]);
}
void addtree(int x,it y) {
int s = M+x;tre[s] = y;s >>= 1;
while(s) tre[s] = merg(tre[s<<1],tre[s<<1|1]),s >>= 1;
}
it findtree(int l,int r) {
if(l > r) return it(r+1,l-1);
it as = it();
int s = M+l-1,t = M+r+1;
while(s || t) {
if((s>>1) != (t>>1)) {
if(!(s&1)) as = merg(as,tre[s^1]);
if(t & 1) as = merg(as,tre[t^1]);
}else break;
s >>= 1;t >>= 1;
}return as;
}
int findl(int x) {
it as = findtree(1,x-1); return as.r;
}
int findr(int x) {
it as = findtree(x+1,n); return as.l;
}
int a[MAXN];
LL dp[205][205],sum[205];
LL DP(int *s,int n) {
if(n < 1) return 0ll;
sum[0] = 0ll;
for(int i = 1;i <= n;i ++) {
sum[i] = sum[i-1] + s[i];
dp[i][i] = 0;
}
for(int i = 2;i <= n;i ++) {
for(int j = i-1;j > 0;j --) {
dp[j][i] = 1e18;
for(int k = j;k < i;k ++) {
dp[j][i] = min(dp[j][i],dp[j][k] + dp[k+1][i]);
}
dp[j][i] += sum[i] - sum[j-1] + i-j;
}
}
return dp[1][n];
}
int main() {
n = read();
for(int i = 1;i <= n;i ++) {
a[i] = read();
}
maketree(n);
L = read();R = read();
LL ans = 0;
for(int i = 1;i <= L-1;i ++) {
addtree(a[i],it(a[i],a[i]));
int ll = findl(a[i]),rr = findr(a[i]);
ans += rr-ll-1;
}
sort(a + L,a + R + 1);
for(int i = L;i <= R;i ++) addtree(a[i],it(a[i],a[i]));
int tm[205] = {},cntm = 0;
for(int i = L;i <= R;i ++) {
int j = i;
cntm = 0;
tm[++ cntm] = a[i] - findl(a[i]) - 1;
while(j < R && findl(a[j+1]) == a[j]) {
j ++; tm[++ cntm] = a[j] - findl(a[j]) - 1;
}
tm[++ cntm] = findr(a[j]) - a[j] - 1;
ans += DP(tm,cntm);
i = j;
}
for(int i = R+1;i <= n;i ++) {
addtree(a[i],it(a[i],a[i]));
int ll = findl(a[i]),rr = findr(a[i]);
ans += rr-ll-1;
}
printf("%lld\n",ans);
return 0;
}
二叉搜索树TREE(线段树,区间DP)的更多相关文章
- 二叉搜索树 [四边形不等式优化区间dp]
二叉搜索树 [四边形不等式优化区间dp] 题目描述 有 \(n\) 个结点,第 \(i\) 个结点的权值为 \(i\) . 你需要对它们进行一些操作并维护一些信息,因此,你需要对它们建立一棵二叉搜索树 ...
- [LeetCode] 538. 把二叉搜索树转换为累加树 ☆(中序遍历变形)
把二叉搜索树转换为累加树 描述 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和. ...
- 从二叉搜索树到AVL树再到红黑树 B树
这几种树都属于数据结构中较为复杂的,在平时面试中,经常会问理解用法,但一般不会问具体的实现,所以今天来梳理一下这几种树之间的区别与联系,感谢知乎用户@Cailiang,这篇文章参考了他的专栏. 二叉查 ...
- Java实现 LeetCode 538 把二叉搜索树转换为累加树(遍历树)
538. 把二叉搜索树转换为累加树 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和 ...
- [Swift]LeetCode538. 把二叉搜索树转换为累加树 | Convert BST to Greater Tree
Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original B ...
- 538 Convert BST to Greater Tree 把二叉搜索树转换为累加树
给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和.例如:输入: 二叉搜索树: ...
- Leetcode 538. 把二叉搜索树转换为累加树
题目链接 https://leetcode.com/problems/convert-bst-to-greater-tree/description/ 题目描述 大于它的节点值之和. 例如: 输入: ...
- LeetCode 把二叉搜索树转换为累加树
第538题 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和. 例如: 输入: 二叉 ...
- 数据结构中的树(二叉树、二叉搜索树、AVL树)
数据结构动图展示网站 树的概念 树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合.它是由n(n>=1)个有限节点组成一个具有 ...
随机推荐
- 记一次APP渗透登录验证绕过思路
前言: 起初是抓包时候查看返回状态码不一致,所以觉得是否可以通过修改状态码来达到绕过的目的,但是拦截响应包再替换手速不够,技术大哥就去搜了下,找到了一个方法,可以自动替换响应包内容. 在偏下方一点的地 ...
- Vue2自定义插件的写法-Vue.use()
最近在用vue2完善一个项目,顺便温习下vue2的基础知识点! 有些知识点恰好没用到时间一长就会淡忘,这样对自己是一种损失. 定义一个对象 对象里可以有任何内容 但install的函数是必不可少的,因 ...
- 命令行工具tabby--gi t仓库Token的使用
命令行工具tabby--git仓库Token的使用 欢迎关注H寻梦人公众号 前言 再见 Xshell !这款开源的终端工具逼格更高! 终端神器--Tabby Terminal electerm is ...
- Python自动化办公:27行代码实现将多个Excel表格内容批量汇总合并到一个表格
序言 (https://jq.qq.com/?_wv=1027&k=GmeRhIX0) 老板最近越来越过分了,快下班了发给我几百个表格让我把内容合并到一个表格内去.还好我会Python,分分钟 ...
- NC14247 Xorto
NC14247 Xorto 题目 题目描述 给定一个长度为 \(n\) 的整数数组,问有多少对互不重叠的非空区间,使得两个区间内的数的异或和为 \(0\) . 输入描述 第一行一个数 \(n\) 表示 ...
- (零)机器学习入门与经典算法之numpy的基本操作
1.根据索引来获取元素* 创建一个索引列表ind,用来装载索引,当numpy数据是一维数据时:一个索引对应的是一个元素具体的例子如下: import numpy as np # 数据是一维数据时:索引 ...
- CMU15445 (Fall 2019) 之 Project#2 - Hash Table 详解
前言 该实验要求实现一个基于线性探测法的哈希表,但是与直接放在内存中的哈希表不同的是,该实验假设哈希表非常大,无法整个放入内存中,因此需要将哈希表进行分割,将多个键值对放在一个 Page 中,然后搭配 ...
- abstract,抽象修饰符
//abstract 抽象类:类由extends继承继承表现在单继承(接口可以多继承)//abstract--约束~~有人帮我们实现抽象方法,只有方法名字,没有方法实现1.不能靠new这个抽象类,只靠 ...
- APISpace 分钟级降水预报API接口 免费好用
各种不同类型的降水对国民经济和国防建设会产生不同的影响.无论农业生产.航空.航海.交通运输.水利建设.防涝防旱等都需要以及准确的降水预报. 分钟级降水预报API,支持国内任一经纬度的预报数据,实时 ...
- ooday04 Java_面向对象_重写_static
方法的重写(override/overriding):重新写.覆盖 发生在父子类中,方法名相同,参数列表相同 重写方法被调用时,看对象的类型------------这是规定,记住就OK 当派生类觉得超 ...