随笔分类 -  数据结构

摘要:比较好的 AC自动机算法详解..【转】http://www.cppblog.com/mythit/archive/2009/04/21/80633.html个人总结:【图是盗用的..】ac自动机是用来求出:给出n个单词,和一篇文章arr[],问arr中出现了多少个单词..第一步:根据给出的n个单词构造一棵字典树第二步:根据字典树完成失配指针第三步:枚举文章中的每个字符,并根据拥有了失配指针的字典树 查找 出现的单词个数以单词:saysheshrheher 文章:yasherhs 举例:第一步:根据给出的n个单词构造一棵字典树 1 const int kind = 26; 2 struct n. 阅读全文
posted @ 2014-03-20 16:25 Griselda. 阅读(243) 评论(0) 推荐(0)
摘要:题意: 在给出的区间内求出最大买进卖出的差价。思路: 对于弱数据:维护一个从左到右的最大差价和最小值。即当发现当前值比最小值小的时候更新最小值,否则看一下当前值与之前最小值的差价是否比最大差价大,是就更新最大差价。时间复杂度是O(m*n) 对于强数据:利用线段树维护一个最大差价、最大值和最小值,查询的时候求出询问的范围内左右子树的最大差价,然后再利用RMQ求出[l, mid]的最小值和[mid+1, r]的最大值,然后返回max(df[rt 2 #include 3 #include 4 #include 5 using namespace std; 6 7 const int... 阅读全文
posted @ 2013-11-20 15:21 Griselda. 阅读(303) 评论(0) 推荐(0)
摘要:题意: 给出一个有n个数的数列,并定义mex(l, r)表示数列中第l个元素到第r个元素中第一个没有出现的最小非负整数。 求出这个数列中所有mex的值。 思路: 可以看出对于一个数列,mex(r, r~l)是一个递增序列 mex(0, 0~n-1)是很好求的,只需要遍历找出第一个没有出现的最小非负整数就好了。这里有一个小技巧:1 tmp = 0;2 for (int i = 1; i = 1; --i) {2 if (mp.find(arr[i]) == mp.end()) next[i] = n+1;3 else next[i] = ... 阅读全文
posted @ 2013-11-20 14:54 Griselda. 阅读(644) 评论(0) 推荐(0)
摘要:题意: 给出一个数组,问你对于第i个数,从最后一个比它大的数到它之间比它小的数中最大的那个数的下标,以及它右边到第一个比它大的数中比它小的数中最大的那一个数的下标。 eg:5 2 4 3 1 l 0 0 2 0 0 对5来说左边比它小的数没有,所以是0。对2来说左边比它小的数没有,所以是0。对4来说左边比它小的数是2,所以下标是2。 r 3 0 4 5 0 对5来说右边比它小的数中最大的是4,是第3个,所以答案是3。对2来说右边比它小的数是1,但是4比2大,所以无法到达1,所以答案是0。对于4,右边比它小的数中最大一个3的下标是4,所以答案是4。思路: 单调队列... 阅读全文
posted @ 2013-07-26 14:58 Griselda. 阅读(682) 评论(0) 推荐(0)
摘要:题意: 给出多个串,如果没有一个串是别的串的前缀,则这些串是符合要求的,输出“Set * is immediately decodable”; 否则输出 "Set * is not immediately decodable"; 输入中多个串以9表示输入结束思路: 裸的字典树,先根据多个串建树,然后遍历每一个串看是否在字典树中.. Tips: 要注意找的时候应该判断是否为叶子结点,而不是仅仅判断是否在字典树中,因为建树的时候肯定存在该串.. Code: 1 #include <stdio.h> 2 #include <cstring> 3 #incl 阅读全文
posted @ 2013-06-06 20:38 Griselda. 阅读(233) 评论(0) 推荐(0)
摘要:题意: 有3个操作 D a 毁坏某一个点a R 修复上一次破坏的点 Q a 问a点附近连续的点有几个思路: 区间合并类的线段树 结构体表示 { l:节点的左界限 r:节点的右界限 ll:左起连续的点数 rr:右起连续的点数 mm:整个范围内连续最长的点数 }Tips: 主要是更新那一块要考虑父节点可能是由左右节点边界合并的 询问那一块要考虑是否可以和兄弟节点合并Code: 1 #include <stdio.h> 2 #include <cst... 阅读全文
posted @ 2013-06-05 16:32 Griselda. 阅读(171) 评论(0) 推荐(0)
摘要:题意: n个数编号从1~n..但是并不按顺序排列.. 现在想把他们互换位置最后得到1~n的序列.. 两个数可以交换位置的条件是 |i-j| == bi 输入:n 表示n个数 a[1], a[2], a[3]..a[i]..a[n] b[1], b[2], b[3]..b[i]..b[n]思路: 并查集.. 可以这么看..如果两个数在一个集合里,那么这两个数就可以互相交换位置了.. 所以就按照i+-b[i]把可以交换的位置的数和该数的归在一个集合里.. 最后查看是否所有要改的数都在一个集合里..Tips: 加的时候加的应该是a[i], 表示把这些数放在一个集合里... 阅读全文
posted @ 2013-04-27 09:43 Griselda. 阅读(185) 评论(0) 推荐(0)
摘要:前序:这题是2011年亚洲赛区的弱化版题目..原题(ZOJ 3544)是画三角形和圆形还有矩形题意:在一个屏幕上画q个带颜色的矩形问9种颜色各占了几个格子输入数据给出屏幕的长n(n <= 200) 宽m(m <= 50000) 和 q个矩形(q <= 50000)接下来q行给出每个矩形的起始位置和长、宽以及矩形的颜色最后输出9个颜色各占几个格子思路:先读入数据..然后从最后一个矩形开始处理..因为越后画的矩形肯定越靠前..即最后画的矩形肯定完全没有被覆盖..然后我们把最后一个矩形覆盖的地方标记出来..再处理倒数第2个矩形............................ 阅读全文
posted @ 2013-01-16 17:52 Griselda. 阅读(220) 评论(0) 推荐(0)
摘要:题意:只有一组数据,数据量为20M根据单词出现顺序输出出现次数..思路:3种方法:① map ② BKDR求hash值<hash表的线性再散列方法或者是链表形式>map的方法因为数据量很大..容易超时Tips:※ BKDR求字符串hash值方法:View Code 1 unsigned int BKDRHash(char *str) 2 { 3 unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. 4 unsigned int hash = 0; 5 6 while (*str) 7 { 8 ... 阅读全文
posted @ 2013-01-14 23:15 Griselda. 阅读(672) 评论(0) 推荐(0)
摘要:题意: 给出一些表达式..求出表达式的和.. 然后判断这些表达式是否可以组成一串首尾相连的数字串.. P.S. 如果有多组答案则按字典序给出..思路: 栈的应用求出表达式.. 深搜求欧拉路径.. Tips: 如果有可行解则在深搜过程到尾的时候就输出~ 否则的话因为是栈的应用~可能返回的过程中会导致答案的更改..Code:View Code 1 #include <stdio.h> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cty 阅读全文
posted @ 2012-11-05 20:32 Griselda. 阅读(201) 评论(0) 推荐(0)
摘要:题意: 给出一个表达式..包含'+' '-' '*' '/' '.' 以及空格.. 求出表达式的值..思路: 栈的应用..Tips: ①. 指针引用那里..参数是字符串首地址不可以改变.. 而如果是指针..就可以改变..所以把字符串首地址作为参数传给change函数不可以..但是先传给函数calculate变成了指针再传给change就可以arr++了.. ②. 运算符优先级可以用一个二维数组来判断..Code:View Code 1 #include <stdio.h> 2 #include < 阅读全文
posted @ 2012-11-05 20:27 Griselda. 阅读(220) 评论(0) 推荐(0)
摘要:题意: 给出一些集合和原来的集合进行多种运算,输出运算后的结果.. 输入: T a b 表示是原集合与该集合进行T操作~ 一开始集合为空.. 最后输出结果~如果是空集合就输出empty set思路: 这道题巧妙的地方是根据集合操作的特点把运算改成了成段的数据更新.. 线段树延迟标记延迟了更新的结果.. 根据集合操作的特点.. 可以看出: U:把区间[l,r]覆盖成1 I:把[-∞,l)(r,∞]覆盖成0 D:把区间[l,r]覆盖成0 C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换 S:[l,r]区间0/1互换 其中如果... 阅读全文
posted @ 2012-10-28 20:46 Griselda. 阅读(217) 评论(0) 推荐(0)
摘要:题意: 给出了n份海报的贴在board上的起始位置和结束位置 问最后可以看到多少份海报 输入: n表示有n份海报 接下来n行 每行 a b 表示海报占据了a~b的位置..思路: 线段树成段更新 用树的结点value表示控制范围内的海报编号.. 因为不用更新到底+查询到每一个叶子节点..所以提高了查询和更新效率.. 其中因为海报长度给的很大.. 所以可以使用离散化来减少空间的消耗以及查询和更新时的递归次数..Tips: 因为给出的a b 表示的是在a~b内贴了海报.. 所以a b给的是值..但是表示的是一段范围.. 如果用正常的离散化..就可能出现 最底下一层贴了一张海... 阅读全文
posted @ 2012-10-26 07:42 Griselda. 阅读(310) 评论(0) 推荐(0)
摘要:题意: 给出一些值 然后给出你一些命令 按照命令输出 命令: C a b c 表示更新a ~ b的值加上 c Q a b 表示查询a~b的和输入: n m 表示有n个数 m 个操作 接下来 m 行为命令行思路: 就是简单的线段树成段更新求和 Tips: ※ 询问的时候要 pushdown ※ 注意范围问题吖~Code: View Code 1 #include <stdio.h> 2 #include <cstring> 3 using namespace std; 4 #define LL long long 5 6 const int MAXN = 100010;. 阅读全文
posted @ 2012-10-17 21:37 Griselda. 阅读(322) 评论(0) 推荐(0)
摘要:题意: 一群小孩顺时针坐然后在玩约瑟夫环的游戏.. 从第k个小孩开始..每个被选中的孩子扔出手中的纸牌.. 然后按着纸牌上面的数找下一个被选中的小孩.. 如果牌中的数是正数就顺时针数.. 如果是负数就逆时针数.. 其中第 i 个被选中的小孩会得到f( i )颗糖.. f( i )表示 i 的正因子个数.. 要求是找出得到糖最多的孩子个数.. 输入: n k 表示有n个小孩..从第k个开始 接下来 n 行有n个小孩的名字和他手上的牌的编号..思路: 一开始想的是暴力找出这个小孩.. 但是会很麻烦.. 然后这里就用到了反素数了.. 反素数:<http://ac... 阅读全文
posted @ 2012-10-16 12:48 Griselda. 阅读(385) 评论(0) 推荐(0)
摘要:题意: 动态更新一段区间的值.. 最后输出总区间的和..思路: 其实就是线段树的成段更新.. 用到了lazy[] 表示懒惰标志.. 懒惰标记: 就是每次更新不更新到最后..而是更新到包含了区间的最大的节点.. 然后如果下次更新的时候更新到了上次已经更新到的节点.. 那先把上次更新暂停的节点往下更新..直到这次更新的区间最大的节点没有被标记.. 这样就省时间了..Tips: pushdown节点就是用来向下更新的.. 要注意的是modify函数..即每次更新的时候 把根节点标记为要更新的数 x 然后顺便求出最大值sum[rt].. ... 阅读全文
posted @ 2012-10-12 11:21 Griselda. 阅读(1842) 评论(0) 推荐(0)
摘要:题意: 给出一些人要求插入队列的位置和他们的身高 输出最后队列的每个人身高输入: 给出n 表示有n个人 给出每个人要插进的队列的位置和该人的身高思路: sum 数组保存该区间的空位 a 数组保存该位置的人的身高 pushup函数用来自下向上更新区间空位 modify函数用来根据sum值找出空位并插入..Tips: 比较的时候..如果比左节点的sum值大就往右子树插位置.. 所以比较函数写的应该是..if(p <= sum[rt<<1]) 往右子树插的时候传入的参数也应该相应减少..即p - sum[rt<<1]Code:View Code 1 //模拟链表 数据量 阅读全文
posted @ 2012-10-11 20:49 Griselda. 阅读(274) 评论(0) 推荐(0)
摘要:题意: 一个board的面积是h*w..在上面贴一些announcement.. 给出告示的宽度ww..可知告示的面积为1*ww.. 问告示是否可以贴上去..可以就输出在board的第几行..不可以就输出-1思路: 以min(h, n)为长度建一棵树.. 然后每一个的叶子的长度为w.. 找出所有叶子中最大的那个..把announcement贴上去.. 用ma数组存当前区间最大值..Tips: 查询和更新可以一起写..但是我分开写了.. 然后还有一个要注意的是..树的最大宽度为min(h, n) 比较的时候是和左右节点大小比.. ※ 所以modify的时候判断条件也应该是i... 阅读全文
posted @ 2012-10-11 13:03 Griselda. 阅读(557) 评论(0) 推荐(0)
摘要:题意: 给出n个数..问循环排序后的最小逆序数思路: 根据出现次序..用线段树的sum记录某一区间出现次数.. 把出现的数值a[i] 更新到 sum[a[i]].. 根据题意..当每一次更新的之前..都对当前位置到最后位置出现的数进行查询.. 即可得到出现比该值早而又比该值大的数的个数..即满足逆序数对的定义.. 所以求和就可得到逆序数对的值.. 当每一次把队头的值移到队尾.. 逆序数对就减少了当前值(a[i]-1)<逆序数对包含该值的都没有了..>.. 但是还有一些逆序数对增加了..(加入到队尾时可与该数组成逆序数对的..)即n-a[i]对.. 所以每一次循环后存在的逆序数... 阅读全文
posted @ 2012-10-10 22:02 Griselda. 阅读(571) 评论(0) 推荐(0)
摘要:[1166 敌兵布阵]题意: 给出一些命令..要求可以: 随时增加或减少某个位置上的数 随时查询某段区间上的和.. 输入: 一个T 表示有T组样例 每组样例一个n 表示有n个位置 输入命令: Add a b 表示在 a 位置上增加 b Sub a b 表示在 a 位置上减少 b Query a b 表示求 a 到 b 的和思路: 因为数据量很大..所以无法靠暴力来遍历求和.. 所以用线段树..Tips: 更新的时候注意sum数组开到节点的4倍Code:View Code 1 #include <stdio.h> 2 #include <cstri... 阅读全文
posted @ 2012-10-09 21:12 Griselda. 阅读(334) 评论(0) 推荐(0)