随笔分类 -  线段树 树状数组 RMQ

摘要:pku 1436 Horizontally Visible Segments题意:在水平坐标系内,有n条垂直线段,问任意三条线段组成一组,问有多少组线段满足,其中任意俩条线段水平可见。水平可见满足:存在一条水平线段将俩条线段连接起来,并且中间不与其他任意线段有交点分析:这是一个染色的问题。首先将线段按横坐标进行排序,接着,从左往右判断当前线段与左边的线段是否水平可见。问题转换:将线段的编号理解为该线段的颜色,那么判断该线段与前面已经插入的线段是否水平可见,只需在查询过程中判断与该区间相交的区间是否存在整个被染成某一种颜色,如果是,则该区间的颜色标号代表的线段与当前线段水平可见。这里要注意查询与 阅读全文
posted @ 2011-09-22 11:46 枕边梦 阅读(293) 评论(0) 推荐(0)
摘要:为什么这样就过了,比赛的时候怎么改都WA了,我只不过把条件改得更严格一点,把多余的判断去掉而已;hdu 4046 Panda题意:给你一个字符串,由'w'和 'b' 组成,对该字符串有俩个操作,当输入为0时,询问该区间[a,b] 内有多少个串 为 "wbw";当输入为0时,将下标为k的字符改为输入的字符;注意:这里的a,b,k表示的都是字符串的下标,也就是取值范围为[0,n-1];分析:对这种区间修改或询问的题目,首先想到的就是线段树或者树状数组了,不过还是线段树熟悉一点,我用线段树做的 ,关键还是构造模型,区间内每一个点的值表示的是什么?我 阅读全文
posted @ 2011-09-19 15:13 枕边梦 阅读(369) 评论(0) 推荐(0)
摘要:pku2886 Who Gets the Most Candies?题意: 有一排编号为1~N的小孩顺时针围成圈,每人手上有一张编号为a[i]的卡片,游戏从第K个小孩开始,他亮出自己的卡片数字,若a[i]大于0,那么左数第a[i]个小孩出圈,否则右数第a[i]个小孩出圈,游戏一直进行,知道所有孩子都出圈,第p个出圈的将会得到f(p)个糖果,f(p)表示p的因子数,问谁拿到的最多的糖果。分析:其实我是先知道 了用线段树做,才拼命想该用线段树怎么做的。思路大致是这样的:每次都默认是从剩下的第一个开始数,顺时针让第count个人出圈。所以必须在每一个人出圈时,算出他左边有多少,再通过他手上的卡片值a 阅读全文
posted @ 2011-09-17 13:55 枕边梦 阅读(254) 评论(0) 推荐(0)
摘要:pku 2828 Buy Tickets题意:给定N(1<=N<=200000)个整数对(pos,val),表示在pos右边 的位置插入一个值val,求经过N次操作之后的val序列的排序情况分析:经典的逆推问题,倘若按照题目给你的顺序进行序列的维护操作,TLE是肯定的。这时,需要注意到,最后一个插入的值位置的固定的,也就是最后一个插入的值可以在它想要插入的位置,所以,先保存所以整数对,之后在倒序插入序列中。那到底应该用什么数据结构实现呢?这里我们发现,可以用线段树来解决这一问题,每一个区间添加一个域 num,表示该区间还能放置的位置数,或者说,表示该区间还能放置的最大的序号值(当然 阅读全文
posted @ 2011-09-16 09:54 枕边梦 阅读(272) 评论(0) 推荐(0)
摘要:题意:将题目的背景去掉,简单的说,就是每一次对一个区间的所有值都分别做一次求平方根的运算,就是将那个值改为它的平方根的值,每次再询问一段区间内的总和分析:很明显的用线段树来做,不过明显的对线段树还是不熟悉,一开始将每一步update操作都更新到具体的每一个点了,没有任何技巧,直接TLE;很明显,如果每一步都必须更新的具体每一个点的话,就是一个O(n)复杂度的操作了,这个对使用线段树来说,没太大意义了。这题目而言,我们发现,任何一个2^63次方以内的数,开根号都至多开八次,也就是,多次询问操作之后,很多都已经不需要update了,所以,只需要在每一个节点中增加一个域,用来标记该区间是否已经全部更 阅读全文
posted @ 2011-09-14 20:49 枕边梦 阅读(286) 评论(0) 推荐(0)
摘要:悲剧呀,这道题目搞了那么久,原来是离散化的方法出现问题了,悲剧,实在悲剧线段树+离散化 今天做了这道题目的时候,也算是明白了离散化的基本意思,因为题目的数据范围很大,1-10000000,直接线段树的话,先不说内存会不会爆,这么大的范围估计也是TLE了.仔细读题,可以看到1<=N<=10000,也就是说最多只有10000个点,如果每个点都不同,那么最多也只有20000个数据,那么离散后的范围就相当小;离散化的大概思路:比如说给你一组数据141000100000,如果直接开线段,显然是浪费,那么我们只要进行映射:1142100031000004接下来我们只要对1234建立线段树就行了 阅读全文
posted @ 2011-05-01 13:15 枕边梦 阅读(373) 评论(0) 推荐(0)
摘要:基础的线段树区间修改和区间求和贴代码吧#include <stdio.h>#define N 100010struct Node{ int l,r; __int64 c,sum;//用c来存储在这个节点存储的增值,用sum来存储在该节点对应的区间上的和。 }p[3*N];int que[N];void build(int k,int s,int t){ int kl,kr,mid; p[k].l=s;p[k].r=t;p[k].c=0; p[k].sum=que[s]; if(s==t) return ; mid=(s+t)>>1;kl=k<<1;kr=kl 阅读全文
posted @ 2011-04-28 21:47 枕边梦 阅读(218) 评论(0) 推荐(0)
摘要:先来谈谈lazy思想。做了这么多的线段树,应该总结一下,lazy是一个很经典的思想。所谓lazy,就是懒惰,每次不想做太多,只要插入的区间完全覆盖了当前结点所管理的区间就不再往下做了,在当前结点上打上一个lazy标记,然后直接返回。下次如果遇到当前结点有lazy标记的话,直接传递给两个儿子,自己的标记清空。这样做肯定是正确的。我们以染色为例,可以这样想,如果当前结点和它的子孙都有lazy标记的话,必定是子孙的先标记,因为如果是自己先标记,那么在访问子孙的时候,必定会将自己的标记下传给儿子,而自己的标记必定会清空,那么lazy标记也就不存在了。所以可以肯定,当前的lazy标记必定覆盖了子孙的,. 阅读全文
posted @ 2011-04-28 21:37 枕边梦 阅读(919) 评论(0) 推荐(0)