首页 > 其他分享 >线段树二分

线段树二分

时间:2024-01-22 22:45:46浏览次数:37  
标签:二分 log res 线段 儿子 复杂度 查询 节点

问题描述

维护长度为 \(n\) 的序列 \(a\),支持以下操作:

  • 1 i x:把 \(a_i\) 修改为 \(x\)。
  • 2 i x:询问最小的 \(j\) 满足 \(j>=i\) 且 \(a_j>=x\)。

\(1\leq n \leq 10^6\)

解决方法

在线段树外直接二分可以做到 \(O(n\log^2n)\) 的时间复杂度,加上简单的剪枝可能效率会高一些,但都无法光明正大地通过这道题。

考虑直接在线段树上二分。叶子节点就直接返回,对于非叶子节点,如果左儿子在查询区间内且左儿子的最大权值大于等于查询的值,就先往左儿子查询,查到了就直接返回,然后再往右儿子查询。

代码:

int query(int u, int x, int k)
{
	if(t[u].a == t[u].b) return t[u].v > k ? t[u].a : N; // v 表示节点代表的区间的最大值
	int ls = u << 1, rs = ls | 1, res = N;
	if(t[ls].b >= x && t[ls].v > k) res = query(ls, x, k);
	if(res < N) return res;
	if(t[rs].v > k) res = query(rs, x, k);
	return res;
}

时间复杂度分析

最坏的情况应该是这样的:从根节点到一个节点,先往左儿子走并且没找到,然后往右儿子走并找到了。从根节点到当前节点的过程中,它不可能存在往左儿子走但找不到,因为如果是这样这个当前节点的区间一定是被查询区间完全包含的,不会有尝试但不能找到,时间复杂度 \(O(\log n)\);递归左儿子但没有答案,说明左儿子中大于查询的值的位置是在查询区间左边的,所以它只会往左儿子递归,则时间复杂度是 \(O(\log n)\);往右儿子走之后,节点区间会被完全包含在查询区间里面,所以后面走的路径一定可以找到答案,时间复杂度是 \(O(\log n)\)。综上,单次查询的时间复杂度是 \(O(\log n)\) 的。

其它应用

CF19D:查询一个点右上角最左边最下边的点。与原问题相似,只需加上离散化并用 set 维护即可。

查询序列第 \(i\) 个位置后面第一段连续的长度为 \(k\) 的 1。

其它任何你能想到的用线段树维护的东西基本上都可以套上线段树二分的模型。

标签:二分,log,res,线段,儿子,复杂度,查询,节点
From: https://www.cnblogs.com/recollect-the-past/p/17981262

相关文章

  • 二分搜索应用 II
    目录1.题目列表2.应用2.1.Leetcode410.分割数组的最大值2.1.1.题目2.1.2.解题思路2.1.3.代码实现1.题目列表序号题目难度1410.分割数组的最大值困难2.应用2.1.Leetcode410.分割数组的最大值2.1.1.题目410.分割数组的最大值给定一个非负整......
  • 【LeetCode】704. 二分查找
    题目:704.二分查找解题思路思路:给定一个nums数组,注意数组是升序排列的;那么,找到当前target元素是否存在于数组之中,可采用二分法查找注意:此处定义该数组区间定义:【左闭右闭】/【左闭右开】使用left指向数组头,right指针指向数组尾,mid用于计算二分查找的位置,mid=left+(ri......
  • CF-240-F-线段树
    240-F题目大意给定一个长为\(n\)的字符串,由小写字母组成。由\(m\)次操作,每次操作给定一个区间\([l,r]\),要求你把区间中的字符进行重新排列,要求重排后的子串是字典序最小的回文串,如果无法得到回文串则忽略这次操作。输出\(m\)次操作之后的字符串。Solution涉及区间操作,考虑用......
  • CF-242-E-线段树
    242-E题目大意给定一个长为\(n\)的数组\(a\),\(q\)次操作,操作分两种:\(1.l,r\):输出\({\sum_{i=l}^{r}a_i}\)。\(2.l,r,x\):把区间\([l,r]\)中的元素都异或上\(x\)。Solution区间信息具有可并性,线段树能够快速得到所求区间的信息。线段树节点中维护一个数组\(bit\),\(bit[i]\)......
  • BZOJ1717 Milk Patterns 产奶的模式 (二分+后缀数组+height数组)
    发现这样起标题更能引流(ylg实锤了)题意给定一个长度为\(n\)的数组\(a\),求在\(a\)中出现了至少\(k\)次的最长子串的长度。解法考虑将一个子串拆成两个后缀,即\([l,r]=[l,n]-[r,n]\),发现一个长度为\(x\)的子串\(t\)在\(i,j\)两个位置出现过当且仅当后缀\(i,j\)有......
  • 数据结构——线段树 入门以后 学习笔记
    数据结构——线段树入门以后学习笔记入门笔记有时间写。才发现我不会线段树。/ll可以看出来我很喜欢class/cf有的代码需要前置:usingll=longlong;constexprllmod=998244353;constexprintroot=1;P3372线段树1classseg_t{private:structemm{......
  • 学习笔记——线段树
    线段树(SegmentTree)1.建树首先我们要明白线段树中的每个节点都代表一个区间,而对于线段树中的每个内部节点\(\left[l,r\right]\),它的左子节点是\(\left[l,mid\right]\),右子节点是\(\left[mid+1,r\right]\),其中\(mid=(l+r)/2\)(向下取整)。然后我们可以让根节点的编号为\(......
  • 代码随想录算法训练营第一天| LeetCode704 二分查找,LeetCode35,LeetCode34,leetcode27.
    LeetCode704题目链接:704.二分查找-力扣(LeetCode)第一时间的想法:简单来说,二分法给我的印象就是想一条绳子上打很多的结,每次对折正好是一个结点,我们需要找到想要的结点比如(a)代码思路就是不断对折一直到绳子两端重合中间没有结点,最后剩下的就是要找的结点a了。......
  • 基础算法(三)二分查找---以“数的三次方”为例
    数的三次方根给定一个浮点数 n,求它的三次方根。输入格式共一行,包含一个浮点数 n。输出格式共一行,包含一个浮点数,表示问题的解。注意,结果保留 6 位小数。数据范围−10000≤n≤10000输入样例:1000.00输出样例:10.000000题解如下#include<iostream>usingnamespace......
  • 【学习笔记】整体二分
    一.整体二分概念整体二分的主体思路就是把多个查询一起解决,是一个离线算法。其要求:询问的答案具有可二分性修改对判定答案的贡献互相独立,修改之间互不影响效果修改如果对判定答案有贡献,则贡献为一确定的与判定标准无关的值贡献满足交换律,结合律,具有可加性题目允......