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

摘要:这题用也算是贪心吧,不过这里有一点数学思想。对于要取掉K位的N位数,那么我们留下来的就是N-K位,我们不妨设 T = N - K; 那么我们选择的第一位数的后面就一定要有T-1个数让我们来选,因此第一个数的选择范围就是[1, N-T+1],当我们选取了第一个数后(假设位置为P),我们第二个数的选择范围就是 [P+1, N-T-2]了,一次类推。由于我们要取的是最大的数,所以我们每次都选取区间内的最大值,用线段树来作优化就可以了。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include 阅读全文
posted @ 2012-07-24 00:29 沐阳 阅读(286) 评论(0) 推荐(0)
摘要:该题说的是一个小东西生活在管道内,长度为L,里面有一些蛋糕,现在动态的给定蛋糕的坐标,小东西的坐标初始话为0,当指令为吃蛋糕的时候,小东西将会去吃最临近的蛋糕。现在问你小东西在Q次询问下要走多远的距离。这题用树状数组+二分查找超时了。。 构造出一棵线段树,每个节点保留区间中所有的蛋糕数以及左右蛋糕最近的坐标。维护好线段树即可。代码如下:#include <cstdlib>#include <cstdio>#include <cstring>using namespace std;int L, Q;struct Node{ int num, l, r, lef 阅读全文
posted @ 2012-07-20 21:38 沐阳 阅读(214) 评论(0) 推荐(0)
摘要:该题题义是给定一个公司的结构,然后针对每个员工的一系列操作。由于问题牵涉到一个员工以及一个员工所领导的部门,因此用普通线性结构显然效率太低。这里用到了线段树。step1:首先我们要确定题目是要对给定的点或者是区间进行操作,那么我们自然而然会想到线段树,但是这题还不是直接的线段树,需要对题中给定的关系进行离散话,也就是按 照先序或者是后序遍历进行排序,这样某一个员工所领导的部门下的成员就在物理上连续了,并且我们用两个数组分别记录某个成员所领导的部门的左边界和右边界。step2:有了上一步的操作后,我们就可以进行构树了,按照普通的线段树进行构建,线段树仅仅只是我们处理点和区间的一种数据结构,... 阅读全文
posted @ 2012-07-20 18:29 沐阳 阅读(694) 评论(0) 推荐(0)
摘要:题中定义了什么叫做可见线段。所谓可见线段就是在给定的垂直与x轴的直线中,能够在两个直线之间连接一条平行线,并且这条平行线不与任何其他的直线相交。WA一次,就是因为没有考虑到在建立点树的过程中会出现将 [1, 2] 和 [3, 4] 视为一条连接的直线,所以最后给坐标乘以一个2.代码如下:#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <vector>#include <map>#define MAXN 800 阅读全文
posted @ 2012-03-08 16:24 沐阳 阅读(354) 评论(0) 推荐(0)
摘要:http://poj.org/problem?id=3667经典线段树,不解释了。代码如下:#include <cstdlib>#include <cstring>#include <cstdio> #include <algorithm>#define MAXN 50000 using namespace std;struct{ int l, r; int lmax, rmax, max, cover;}seg[MAXN*4];void build(int f, int l, int r){ int mid = l+r >> 1; 阅读全文
posted @ 2012-03-07 21:21 沐阳 阅读(501) 评论(0) 推荐(0)
摘要:题目大意为给定一段内存快,要求根据命令输出正确的答案。New x 申请长度为x的空白内存的首地址,如果不满足输出Reject NewFree x 释放包含x节点的内存块,注意该内存块为一个New操作所确定的区域,即不必要将物理相邻的内存块视作一个内存块Get x 得到从左到右的第x个内存块Reset 重置总区间针对这些要求,设定一棵线段树,每个节点保留左,右连续空白段,以及区间总长。这样便能够处理New命令,而Free以及Get命令则用vector保留,用二分搜索优化。代码如下:View Code #include <cstdio>#include <cstring># 阅读全文
posted @ 2012-03-07 20:39 沐阳 阅读(479) 评论(0) 推荐(0)
摘要:前面还一位这是一道最长上升子序列的题目,只觉得无从下手,后来得知是最长连续上升子序列,于是有了想法。 (英文不好啊,题目中就能看出来的)对于每一个节点保留其左起及右起连续子序列长度和整个区间的最长连续长度。当然利用这三个信息加之线段树的结构我们就能够得到所要的结果。先说说我自己的写法(后来证明是写复杂了),对于每个询问我定义了三个状态 0, 1, 2。 0 表示该区间内不需要从左边或者是右边开始计算,1 表示求这段区间的右连续, 2 表示这段区间的左连续,然后就是一连串的分解判断,详见代码。该题的调试过程多亏了丽丽同学的帮助,自己生成的数据,用别人AC的代码跑结果,然后再和自己的结果比较... 阅读全文
posted @ 2012-03-04 22:10 沐阳 阅读(212) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=3016这题是一个游戏题,名曰:是男人就下一百层。就是给定一系列的坐标,首先是纵坐标,然后是线段的左右坐标,最后是在该条线段的增加或者扣除的血量。解决这题的关键在于如何处理这多条线段的关系,如果是从上而下的话,那么我们能够更新一条边的两个端点下的最优值,那么对于后面加入的边就有下面的动态方程: sum[f] = max( sum(x), f.x1 <= x <= f.x2 ) + val(f) 需要在该边的区域内寻找最大值来更新这条边的两个端点值,这样做显然处理起来较麻烦,时间开销也比较大。所以我们 阅读全文
posted @ 2012-03-03 09:55 沐阳 阅读(335) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=1540题义是对于一段线段,D x 表示破坏x点,R 表示回复最近一次被破坏的点,Q x表示询问以x点为中心的两头的最长的连续区间。改了2个小时,终于A掉了,吐血啊,尤其是杭电的测试数据,一个点可以破坏多次,这小日本鬼子也忒坏吧,再说了如果一个点破坏多次,八路军叔叔也要修理多次吗,题义与实际既不符合,还是POJ厚道。该题分两部来做,首先是建立一棵线段树,这颗线段树应该保留有一下信息:1. 该区间的左连续长度,右连续长度2. 该区间的覆盖情况(即是否没有发生任何破坏)这是线段树以空间换时间的地方然后就是求连续的区 阅读全文
posted @ 2012-02-28 10:05 沐阳 阅读(651) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=3030该题题义就是给定一个长度为M的A数组,依照这个数组生成一个长度为N的数组,然后求严格增长的子串个数。对于所给定的值进行离散化排序,再巧用树状数组求个数。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <map>#include <algorithm>#define MOD 1000000007#define MAXN 500005using namespace 阅读全文
posted @ 2012-02-26 21:02 沐阳 阅读(439) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=2642裸二维树状数组,题义就是求一块面积内处于发亮状态的星星的个数。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>#include <map>#define MAXN 1005using namespace std; int c[MAXN+5][MAXN+5], N;bool B[MAXN][MAXN];inline int lowbit(i 阅读全文
posted @ 2012-02-26 13:44 沐阳 阅读(261) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=1541题义为给定N个点按照先x轴,后y轴坐标排序,求某一点的左下角的星星数量,刚开始用二维的树状数组来做,结果肯定是内存不过用。该题正解为在给定的坐标点的排序后,只对x轴坐标建立一个一维数组,对于当前状态按x轴将平面划分成M个区域,由于给定的点的y轴坐标一定是当前最高的,所以直接对横坐标前求和即可。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>#incl 阅读全文
posted @ 2012-02-26 11:08 沐阳 阅读(378) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=3887做树状数组专题,竟然还是没有看出这题可以用树状数组来写,表示有点不好意思啊。原来树状数组之所以能够搞定这一题是因为我们在建立好一棵数时,通过反问一个节点的子孙们后,顺序对的变化数来统计有多少数字比该节点小的子孙节点。该题用DFS搜索直接爆栈,所以恶心的写了一个模拟栈,其实要注意的就是每个节点要在第一次出栈时保留在栈,第二次才从栈中出去,亦即是当其孩子节点都被反问完之后。这题还有一点不得不说的就是给定的边的关系没有确定,要建立一个双向的邻接表,这就相对与给定的点可以从不同的方向来看其从属关系,而给定的根节 阅读全文
posted @ 2012-02-25 22:04 沐阳 阅读(453) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=1542该题就是给定N个矩形,求出叠加之后的面积,与求面积交类似,就是覆盖次数没有了要求。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <cmath>#include <map>#include <algorithm>#define MAXN 205using namespace std;struct Node{ double x, y1, y2; in 阅读全文
posted @ 2012-02-25 01:28 沐阳 阅读(352) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=1255题义为给定N个矩形,求其重叠的图形面积,该题采用线段树离散化y轴坐标,并且采用分割思想,只依据x坐标来进行分割。我们将N个矩形化为N*2条线段来处理,该结构体中的成员变量为 x, yl, yh, 分别是x轴坐标,相对高低的y轴坐标,即线段的两个端点值。1.将所有的线段排一次序,并将y轴所有坐标轴点排序并进行离散化;2.在从左往右扫描每一条线段时,我们应该理解为此时我们将把该线段的右边区域认定为全部被覆盖;3.查找该x轴坐标下被覆盖的y轴坐标的次数,因为一旦y轴被覆盖,则说明其右边无限长的区域被覆盖,如果 阅读全文
posted @ 2012-02-24 21:33 沐阳 阅读(753) 评论(0) 推荐(0)
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=1561题目大意就不说了,都中文题...... 该题看起来计较复杂,上课的时候想了想,对于每个节点而言攻击T次,那么分配给孩子节点的次数的组合数是庞大的。然而这道题就是很暴力,DFS下面三重for循环。for循环里面就是背包过程了。吴涛的建议使得程序更加的好,对于每一个递归能够攻击的次数减1,这样能够减少许多不必要的if判断。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <algor 阅读全文
posted @ 2012-02-23 15:01 沐阳 阅读(398) 评论(0) 推荐(0)
摘要:该题题义是求一个序列中非递减的子序列的个数,其实就是一个求逆序对的题,这里当然就是用树状数组来解决了。首先对输入数据进行离散化,以便于在树状数组上面工作,然后利用DP公式计算ans[i] = sum{ ans[j], j < i },可以理解为在前面的所有满足要求的集合上加上这个较大的数。参看http://www.cppblog.com/menjitianya/archive/2011/04/06/143510.aspx代码如下:#include <cstring>#include <cstdio>#include <algorithm>#includ 阅读全文
posted @ 2012-02-19 10:30 沐阳 阅读(391) 评论(0) 推荐(0)
摘要:二维树状数组的模板题了,初始化的时候注意下,不用逐个插入,而是直接用lowbit这个函数。#include <stdio.h>#include <string.h>#include <stdlib.h>#include <math.h>#define MAX 1005int c[MAX][MAX];;inline int lowbit( int x ){ return x & -x; }inline void modify( int x, int y, int val ){ for( int i = x; i <= 1001; i 阅读全文
posted @ 2012-02-15 21:02 沐阳 阅读(461) 评论(0) 推荐(0)
摘要:用树状数组求逆序对数。。。#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#define MAX 3000005#define MaxN 10005using namespace std;int ans[MAX];__int64 c[MaxN];inline void updata( int s ){ while( s < MaxN ) { c[s]++; s += ( s & (-s) ); 阅读全文
posted @ 2012-02-14 21:03 沐阳 阅读(287) 评论(0) 推荐(0)
摘要:前面用二维线段树写了个,代码长不说,而且效率还慢的要死!!!!! Orz...... 这题如果用树状数组来解的话,代码量很小而且速度很快。二维树状数组就在循环上面再加一层循环。 代码如下:#include <cstdlib>#include <cstdio>#include <cstring>#define LOWBIT( x ) (x) & -(x)using namespace std;int rec[1040][1040], N;inline void CinInt( int &t ){ char f = 1, c; while( c 阅读全文
posted @ 2011-09-12 19:20 沐阳 阅读(262) 评论(0) 推荐(0)