![](https://img-blog.csdnimg.cn/20201014180756916.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
线段树和树状数组
文章平均质量分 82
AC_Arthur
Die luft der Freiheit weht
展开
-
玲珑杯 1072 - Capture(DFS序+线段树)
题目链接:点击打开链接思路:不难发现, 这是一棵树, 把树先建立好, 跑dfs序, 然后就变成了线段树区间修改、单点修改、区间最值。细节参见代码:#include #include #include #include #include #include #include #include #include #include #include #include原创 2016-12-24 15:22:02 · 844 阅读 · 0 评论 -
HDU 2227 Find the nondecreasing subsequences(线段树+离散化+DP)
题目链接:点击打开链接题意:给你n个数, 求非递减子序列的个数。思路:很容易想到, 用d[i]表示, 以a[i]为最后一个元素的非减子序列个数。 那么每次转移, 就是sum(d[j]) (其中 j 那么最终答案是所有d[i] (1 细节参见代码:#include#include#include#include#include#include#include#in原创 2016-03-29 16:41:28 · 581 阅读 · 0 评论 -
HDU 4630 No Pain No Game(线段树离线处理)
题目链接:点击打开链接题意:给你一个n的全排列, q个操作, 每个操作是一个区间,要求求出这个区间中任意两个数的gcd的最大值。思路:一个数是两个数的公约数, 等价于一个数可以被两个整数同时整除。 所以我们可以算出每一个数的所有约数, 然后求一个区间中被超过两个数整除的数中的最大值即可。维护区间最大值, 我们可以用线段树来维护。 因为我们难以同时维护一个区间, 所以我们离线处理,原创 2016-03-17 11:41:03 · 1101 阅读 · 0 评论 -
HDU 2836 Traversal(线段树+离散化+DP)
题目链接:点击打开链接题意:给你n个数的序列, 一个数h, 求相邻数之差不超过h的子序列的个数和 % 9901。思路:经典水题, 显然用d[i]表示以a[i]结尾的满足条件的子序列个数。 那么对于j = a[i] - h。 对于这个限制用线段树下标维护, 线段树用来维护d[i]的累加和。 细节参见代码: #include#include#include#include#原创 2016-03-29 17:38:08 · 1568 阅读 · 0 评论 -
ZOJ 3635 Cinema in Akiba(二分+树状数组)
题目链接:点击打开链接题意:n个人轮流做到座位上, 第i个人做到第a[i]个空座上, 求最终每个人的座位情况。思路:经典水题, 二分套树状数组。细节参见代码:#include#include#include#include#include#include#include#include#include#include#include#include#incl原创 2016-03-04 15:06:11 · 1134 阅读 · 0 评论 -
HDU 5618 Jam's problem again (cdq分治+树状数组)
题目链接:点击打开链接题意:给n个点,求每一个点的满足xyz都小于等于它的其他点的个数。思路:经典的cdq分治+树状数组。 方法就是先按照x从小到大排序, 这样,x一定满足后面的大于等于前面的, 这样我们就可以不用管x了, 然后对y进行cdq分治,使得y满足关系, 在此基础上用树状数组顺便维护z坐标。 但是由于cdq分治每次总是要解决左边对右边的影响, 所以在相等时, 每次只更新了右边原创 2016-02-02 10:45:09 · 1923 阅读 · 0 评论 -
Manthan, Codefest 16(G. Yash And Trees(dfs序+线段树))
题目链接:点击打开链接题意:给你一棵树, 根结点为1, q组操作, 每组操作有两种, 一种是对一个结点的所有子树结点的值全部+1, 另一种是查询一个结点的子树结点上值%m的余数为素数的个数。思路:对于第一个操作, 我们可以想到用dfs序给树重新标号, 使得一个结点的子树结点为相邻的一条线段, 这样,就可以很容易的用线段树进行处理了。 对于第二个操作, 为了维护一个区间内的值, 我们可以用原创 2016-03-02 09:00:14 · 1150 阅读 · 0 评论 -
POJ 2886 Who Gets the Most Candies?(树状数组+二分)
对于可以被i整除的数的个数, 我们可以通过枚举每一个数的倍数, 预先处理出来。该题直接模拟就好, 因为每次都一定有一个人出队, 所以要枚举n次 , 对于每次, 要计算具体是哪个人出队, 这个可以用数学推导很快的算出来是当前队列的第几个人, 要找到这个人我们可以用二分+树状数组来优化算法。 复杂度O(n*logn*logn)细节参见代码:#include#include#incl原创 2015-12-26 10:43:05 · 932 阅读 · 0 评论 -
POJ 2828 Buy Tickets(树状数组)
题目链接:点击打开链接题意:给n个人依次插队的情况, 要求求出最终的队伍情况。该题可以用树状数组很方便的维护。如果从前向后扫的话, 每次插队都会影响这个人后面的情况, 所以我们可以倒着进行, 那么最后一个人的位置就是最终位置, 对于前面的人的位置, 只受后面人的影响, 所以等价于其最终位置是第pos[i]+1个空位。 那么也就是说要快速的找到第pos[i]+1个空位。 显然,原创 2015-12-24 20:47:36 · 858 阅读 · 0 评论 -
HDU 2795 Billboard(线段树)
题目链接:点击打开链接题意: 原始序列全为w, 找到最左边的>=a的位置。该题利用线段树递归特点来求其最左边的大于等于a的位置。线段树递归的特点是从祖先结点开始自顶向下递归,访问各个元素的顺序一定是从左到右, 并且在递归之后可以顺便维护区间结点的值。利用这个特点, 我们可以直接查询到>=a的最左边的位置。该元素变成v - a, 然后顺便维护改变了的值。 所以该题就成了维护区间最大原创 2015-12-24 19:51:23 · 1408 阅读 · 0 评论 -
HDU 1394 Minimum Inversion Number(树状数组||线段树)
题目链接:点击打开链接对于求逆序数的问题, 通常用线段树或者树状数组来维护, 树状数组代码短,好写, 还是尽量写树状数组吧。首先求出原始排列的逆序数, 那么对于每一次操作, 因为都是将当前排列的第一个数拿到最后一个位置, 所以答案就增加了所有比他大的数字个数,减小了所有比他小的数字个数。细节参见代码:#include#include#include#include#inc原创 2015-12-24 15:50:47 · 1946 阅读 · 0 评论 -
HDU 1754 I Hate It(线段树-区间求最值&&单点修改)
线段树基础题,区间最值,单点修改细节参见代码:#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#define Max(a,b) ((a)>(b)?(a):(b))#de原创 2015-12-24 11:58:59 · 802 阅读 · 0 评论 -
HDU 1166 敌兵布阵(线段树版)
该题之前用树状数组写过, 最近在学习线段树, 用线段树重新写了一遍。在学习一种新的数据结构之前, 最重要的是要理解其结构是什么样子的, 这个可以参照《算法竞赛入门经典》P199页。 比较重要的是理解好几个变量:1. 每个结点有一个编号。 这个编号对应了其所统治的区间, 我们从线段树的祖先结点开始从上到下, 从左到右的顺序给所有结点编号,这样, 编号为i的结点其左右结点的编号就是2i原创 2015-12-24 10:57:46 · 1144 阅读 · 0 评论 -
Codeforces Round #271 (Div. 2) E. Pillars(线段树优化DP)
题目链接:点击打开链接题意:一个n个数的序列,每个数有一个高度值h[i]。 求一个最长子序列,要求相邻两个数满足| h[i] - h[i-1] | >= d。 并要求打印出该序列。类似于最长上升子序列, DP思想很简单, 但是可惜n太大了, 二重循环会超时。 所以要想办法优化掉第二层循环。观察发现, 第二层所做的事情就是在所有满足j= d 的j中找到最大的d[j]。j 把不等式原创 2016-01-25 17:50:00 · 1288 阅读 · 0 评论 -
HDU 4902 Nice boat(线段树)
题目链接:点击打开链接题意:给n个数, q个操作, 两种操作, 1操作是把[l, r]区间里所有数变成x。 2操作是把[l, r]区间里所有大于x的数变成gcd(a[i], x)。思路:1操作没什么好说的, 对于2操作可以发现, 如果一个数被修改, 那么它一定是变小了, 我们知道一个数在经过不超过loga[i]次后一定会变成1, 所以可以知道, 如果存在很多2操作, 那么最后一定会形成很原创 2016-03-06 19:37:58 · 1485 阅读 · 0 评论 -
Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake(线段树+离散化优化DP)
题目链接:点击打开链接题意:给出n个圆柱体的地面半径和高, 要求只能有一个直接放在桌子上, 其他的要放在他上面, 第i个能放在第j个上面的条件是:当且仅当第i个的体积大于第j个且j 思路:一看就是一个DP, 而且状态很容易表示, d[i]表示到第i个为止能得到的最大总体积。 转移到 max(d[j]) + a[i], (j a[j])。 但是n非常大, 显然要优化, 因为第二层循环原创 2016-02-21 14:27:34 · 1563 阅读 · 0 评论 -
Codeforces Round #200 (Div. 1) D. Water Tree(dfs序+线段树)
题目链接:点击打开链接思路:dfs序其实是很水的东西。 和树链剖分一样, 都是对树链的hash。该题做法是:每次对子树全部赋值为1,对一个点赋值为0,查询子树最小值。该题需要注意的是:当我们对一棵子树全都赋值为1的时候, 我们要查询一下赋值前子树最小值是不是0, 如果是的话, 要让该子树父节点变成0, 否则变0的信息会丢失。细节参见代码:#include #in原创 2016-12-07 19:04:09 · 494 阅读 · 0 评论 -
51NOD 1272 最大距离(线段树)
题目链接:点击打开链接思路:问题简化一下就是, 求任意一个数后面大于等于它的数中距离它的最远距离。 因为有两个特征:“大小”, “距离”, 我们可以用线段树下标表示数的大小, 距离作为值, 就变成了求区间最大值的问题了。细节参见代码:#include #include #include #include #include #include #include #in原创 2016-11-30 14:18:49 · 551 阅读 · 0 评论 -
POJ 3109 Inner Vertices(线段树)
题目链接:点击打开链接思路:题目可以转化成这样的问题: 有多少个白点的上下左右都有黑点, 答案是这样的白点个数 + n怎么求符合要求的白点个数呢?按照常见思路, 我们先对黑点进行排序, 先按x再按y将其分层。 然后我们处理到了第i列, 符合要求的白点一定在相邻的上下两个黑点之间, 我们假设此时相邻两个黑点的y坐标是L和R, 那么我们要求区间[L+1, R-1]里有多少个白点的左右原创 2016-09-07 16:25:15 · 693 阅读 · 0 评论 -
HDU 5828 Rikka with Sequence(线段树)
题目链接:点击打开链接思路:对于该题, 由于存在区间加一个值, 那么所有数都可能永远不会变成1, 但是数与数之间的相对值会趋近于相等。 比如1 2 3 4 5, 进行一次根号操作变成1 1 1 2 2, 而一旦如果相等, 那么他们同时加一个数也是相等的。 所以我们增加一个标记bit[rt]表示该区间内的数是否全部相等,如果相等等于什么。细节参见代码:#include #inc原创 2016-08-11 20:39:37 · 1088 阅读 · 4 评论 -
Ural 1028. Stars(树状数组)
题目链接:点击打开链接思路:为了满足第一个条件, 我们可以先按照x坐标排序, 然后我们用树状数组来维护y坐标大小关系, 就可以在O(nlogn)的时间内求出答案了。细节参见代码:#include #include #include #include #include #include #include #include #include #include #i原创 2016-08-10 20:43:13 · 867 阅读 · 0 评论 -
UVA live 3938 - "Ray, Pass me the dishes!"(线段树)
题目链接:点击打开链接该题需要深刻理解线段树的特点:任意一个父结点所表示的区间都是两个儿子区间的并, 且儿子区间的交为空集。那么我们可以采用分治的思想: 一段区间的最大连续和要么来自左半边, 要么来自右半边, 或者一半在左一半在右。细节参见代码:#include#include#include#include#include#include#include#inclu原创 2016-08-27 18:23:27 · 696 阅读 · 0 评论 -
UVA 501 - Black Box(二分 + 树状数组 + 离散化)
题目链接:点击打开链接思路: 该题虽然是求区间第k小, 但是实际上是不需要用到复杂的数据结构的, 我们只需要用树状数组来维护就行了, 因为以值作为树状数组下标, 那么这就是一个天然的单调区间, 用二分来查找就行了。 另外就是要离散化一下。细节参见代码:#include #include #include #include #include #include #includ原创 2016-04-30 17:12:51 · 3680 阅读 · 0 评论 -
UVA 10869 - Brownie Points II(树状数组+离散化)
题目链接:点击打开链接思路:统计区间和, 我们想到了树状数组, 离散化后, 枚举第一个人选取的x坐标, 用两个树状数组,以y坐标为下标建树, 一个表示当前左边的情况, 一个表示右边的情况, 再枚举当前垂直线上的每个点, 可以用树状数组快速统计结果, 该题题意挺难理解的, 要求输出第一个人的最小得分的最大值ans, 还有就是当第一个人取ans时第二个人的可能得分。细节参见代码:#incl原创 2016-05-10 16:47:41 · 913 阅读 · 0 评论 -
HDU 1828 Picture(线段树 + 扫描线)
题目链接:点击打开链接题意:求n个矩形的周长的并。思路:用扫描线法, 按照x坐标和y坐标分别扫描, 用线段树维护区间覆盖情况, yy了一下, 可以发现, 每次的可见轮廓都等于这次的区间覆盖长度和上一次的差值。细节参见代码:#include#include#include#include#include#include#include#include#include原创 2016-03-11 16:52:18 · 1461 阅读 · 0 评论 -
HDU 1542 Atlantis(线段树求矩形面积并)
题目链接:点击打开链接题意:给你n个矩形, 求这n个矩形所覆盖的面积(重复覆盖算一次)思路:我们可以考虑, 将y坐标保存并排序。 按x坐标离散化后建立线段树。 每次遇到一个矩形的下底边就将这个区间+1, 遇到上边就-1, 每次更新后累加当前x区间的长度乘以相邻两边的高度。 具体原因可以画图看看就明白了。 另外很重要的一点就是, 线段树都是维护一个点集, 但是对于边的问题就会变得很麻烦原创 2016-03-10 17:22:54 · 2522 阅读 · 0 评论 -
HDU 5634 Rikka with Phi(线段树)
题目链接:点击打开链接题意:有3种区间操作, 1是把区间内的所有数变成它的欧拉函数值, 2是把区间所有数都变成一个数x,3是查询区间和。思路:后两个操作就是线段树的区间修改和求和, 没什么好说的。 题解说用平衡树(弱不会), 不过大致思路线段树同样可以维护, 因为一个数进行最多phiO(logn)次就会变成1, 所以我们可以在递归结束,向上传标记的时候顺便看看其子区间是不是都等于1,原创 2016-02-25 13:58:22 · 1467 阅读 · 0 评论 -
HDU 4819 Mosaic(二维线段树)
题目链接:点击打开链接题意:原创 2016-03-08 16:16:50 · 1252 阅读 · 0 评论 -
Educational Codeforces Round 8(E. Zbazi in Zeydabad(树状数组优化))
题目链接:点击打开链接题意:一个n*m矩阵, 里面的格子除了'z'就是'.',问有多少个z形图案。思路:因为n和m很大, 即使n^3复杂度也会超时。 如果按照最朴素的方法, 我们可以处理一下前缀和, 处理出一个格子向左l[i][j]、向右r[i][j]、斜向左下lr[i][j]连着的z到哪里为止, 这样我们用n^2复杂度枚举每一个格子作为z形图案的右上角,取min(l[i][j], lr原创 2016-02-22 21:24:58 · 1691 阅读 · 1 评论 -
1455 - Kingdom(并查集+线段树区间加减)
题目链接:点击打开链接题意:给你n个点,m次询问,每次询问有两种:1. 将城市v和u用一条道路连接起来2.询问用一条水平线能穿过多少个州和这些周中包括的城市数。由于水平线一定是v.5的形式,所以不妨将y坐标乘以2再建立线段树,建两棵线段树,一棵维护大洲的数量,一棵维护城市数。 合并问题交给并查集就好了。另外值得一提的是,对于线段树区间加减这个问题, 其处理方法大家应该更深入原创 2016-01-25 15:25:11 · 1366 阅读 · 0 评论 -
HDU 5493 Queue(二分+树状数组)
题目链接: 点击打开链接题意:有n个人排队,每个人都有一个独一无二的身高,告诉你每个人的身高和他前面或者后面的比他高的人的个数(到底是前是后是未知的)。 要求你还原原来的队列,并且字典序最小。思路: 因为要求字典序最小, 我们可以先按照身高从小到大排序,假设当前到了第i高的人, 他前面或者后面有k个人, 那么他前面的所有人都比他矮, 比他高的还有n-i个人,那么假设他前面还有p个空位,原创 2015-12-23 22:39:29 · 1489 阅读 · 0 评论 -
UVA 11402 - Ahoy, Pirates!(线段树区间更新(标记重叠的处理))
题目链接:点击打开链接题意:有3种区间操作, 将某个区间全部变成1; 将某个区间全部变成0;将某个区间的1变成0, 0变成1。思路:前两个操作就是最基本的区间更新, 用到懒惰标记, 然而第3个操作却有些麻烦, 如果仅仅更新当前这个结点对应的大区间, 那么它所包含的小区间再次更新时就会发生错误, 错误的原因是因为标记的重叠和碰撞。 显然 , 这就是很典型的一个问题, 处理标记碰撞的问题。原创 2016-01-22 16:26:16 · 1650 阅读 · 0 评论 -
HDU 3874 Necklace(树状数组离线处理)
想了一下午没有想到好办法,看了一下别人思路,该题需要离线处理。这个方法可以很好的处理重复数字的问题,用来求解无重复数字的区间和问题。将询问的区间按照右端点排序,每次记录上一个区间的右端点R,然后遍历R到当前区间右端点,用一个数组记录每一个数字出现的位置,如果该数字出现过,那么删除上一次出现的位置的值,并更新到当前位置。 这样就可以有效的去重 。 由于整个过程只是遍历了一遍数组,所以原创 2015-09-22 19:45:51 · 657 阅读 · 0 评论 -
POJ 1990 MooFest(树状数组)
题目链接: 点击打开链接该题是一道很巧妙的树状数组的应用,一开始初学ACM的时候曾经看别人题解做过,然而一丝作用也没有,完全没有理解该题,以至于现在见到和没做过一样。个人认为学习树状数组还是去看一下lrj的蓝书吧,讲出了树状数组维护数据的原理,以及那个bit数组的含义,理解了数据结构原理之后才能随心所欲的运用。该题求任意两个牛的吼叫值只和。 由于两头牛的吼叫值取最大的,所以一原创 2015-09-22 16:08:34 · 768 阅读 · 0 评论 -
Matrix.(POJ-2155)(树状数组)
一道二维树状数组的题目,比较经典,适合新手练习。可以打印出来每次操作后矩阵的情况,就能很直观的理解这个树状数组是怎么实现的,他将多余的部分巧妙的重复了偶数次,使得多余部分奇偶不会发生变化。#include#include#include#include#include#include#includeusing namespace std;int T,n,m,bit[1005原创 2015-05-02 22:09:56 · 1770 阅读 · 0 评论 -
HDU 5497 Inversion(树状数组)
树状数组好题。 我们都知道可以用树状数组求一个序列的逆序数,但是之前一直没有深刻理解为什么要用树状数组,通过该题可以知道,我们正确的思维应该是先面对一个问题,然后思考如何解决问题,然后才能对其中遇到的困难有一个深刻的认识,然后就能知道为什么需要这样解决,为什么要用树状数组。因为我们需要这样的数据结构。该题要求删去一个长度为m的连续序列后逆序数最小值。由于长度是固定的,所以由滑动窗口我们原创 2015-11-09 22:16:03 · 836 阅读 · 0 评论 -
HDU 3743 Frosh Week(树状数组求逆序数)
模板题,有一个坑点,学生编号并不一定是老老实实的1、2、3、.....n这个排列,可能很大,所以一开始RE了。 给编号另分配一个编号,只要满足大小关系就行。细节参见代码:#include#include#include#include#include#include#include#include#include#includeusing namespace st原创 2015-09-22 09:46:23 · 831 阅读 · 0 评论 -
HDU 1754 I Hate It(线段树单点替换/区间最值)
简单线段树基本操作。线段树是一种树状结构,每个结点对应了一个区间,由于该结构是一个典型的二叉树,所以每一层最多只会递归两次,假定根结点长度为pow(2,h),那么结点总数容易计算出来,大约区间长度的两倍,很多人说要开四倍的数组,这其实是针对于非递归写法的,如果用递归写只需要开三倍就够了。其实递归手法很巧妙的,用返回值顺带更新了所有祖先结点。细节参见代码:#includeusing原创 2015-09-29 16:54:43 · 588 阅读 · 0 评论 -
12299 - RMQ with Shifts(线段树单点更新、区间求最值)
该题由于每次操作所改动的数字个数较少,所以直接用单点更新就好了。细节参见代码:#includeusing namespace std;typedef long long ll;const int maxn = 100000 + 10;const int INF = 1000000000;int n,m,a[maxn],q,ql,qr,p,v,minv[3*maxn],b[30];原创 2015-09-27 09:22:56 · 628 阅读 · 0 评论 -
Count Color(线段树+位运算)
这是之前比赛的一道题目,HD训练题上又遇到了,直接A了,其实就是将求和操作变成|=运算符,用位运算压缩T种颜色,这样每个结点上维护的就是其所覆盖的颜色种类数。细节参见代码:#include#include#include#include#include#include#includeusing namespace std;const int maxn = 100000 +原创 2015-09-25 19:11:10 · 778 阅读 · 0 评论