随笔分类 -  数据结构(总)

摘要:一个很长的英文背景,其他不说了,就是告诉你锯一个长度为多少的木板就要花多少的零钱,把一块足够长(不是无限长)的木板锯成n段,每段长度都告诉你了,让你求最小花费。 明显的huffman树,优先队列是个很好的东西。#include #include #include #include #include #define ll __int64using namespace std;int n;struct cmp //优先级重载{ bool operator()(ll x, ll y) { return x > y; }};priority_queue, cmp... 阅读全文
posted @ 2013-12-18 12:06 xindoo 阅读(138) 评论(0) 推荐(0)
摘要:对与知道并查集的人来说这题太水了,裸的并查集,如果你要给别人讲述并查集可以使用这个题当做例题,代码中我使用了路径压缩,还是有一定优化作用的。#include #include const int maxn = 500005;int n, m;int pa[maxn];void init(){ for (int i = 1; i <= n; i++) { pa[i] = i; }}int find(int x){ if (x == pa[x]) return x; return pa[x] = find(pa[x]); //路径压缩,... 阅读全文
posted @ 2013-10-30 16:41 xindoo 阅读(163) 评论(0) 推荐(0)
摘要:这道题第一眼看去很难,其实不然,短短几行代码就搞定了。 说一下大概思路,如果是排成一排的n个人,如 1 2 3 4 5 6 7 8 我们要变成 8 7 6 5 4 3 2 1 需要交换 28次,找规律的话就是 n*(n-1)/2,但这道题是一个圈,要让他们顺序变反的话不一定1要在8的位置上去,4 3 2 1 8 7 6 5 这样也是反的,我们只要把n个人分成两部分,然后按拍成一条线的方法来出来两部分就OK了;#include #include using namespace std;int main(){ int n, t; cin >> t; while (t--) ... 阅读全文
posted @ 2013-10-03 16:34 xindoo 阅读(166) 评论(0) 推荐(0)
摘要:这个题目属于线段树的点更新区间查询,而且查的是整个区间,其实不用写query()函数,只需要输出根节点保存的值就可以了。题意: 输入n,m表示有2^n个数和m个更新,每次更新只把p位置的值改成b,然后输出整个序列运算后的值,而这个运算就比较复杂了, 最下面一层两个数字之间或运算得到原来数目一半的数字,然后两个之间异或运算,得到一半,再或再异或………………,一直到得到一个数字,这个数字就是要求的结果。思路: 如果只是一种运算,这就是简单的线段树点更新,区间查询。而现在,我们要确定什么时候用or 什么时候用xor, 想想看,最下面一层是用or, 总共有n层,因为or和xor是交替进行的,我... 阅读全文
posted @ 2013-08-27 11:19 xindoo 阅读(286) 评论(0) 推荐(0)
摘要:在这里先说一道微软的面试题目———《队列中的最大值》 让你设计一个队列,是其求里面最大值的时间复杂度尽可能的低,但这个队列除了最大值外,就是一个普通的队列,该怎么进出还是怎么进出,并不是优先队列。 对于一堆树,我们求其中最大值一般都会直接遍历一次,然后找到最大值,这样的话时间复杂度是O(n),如果在这道题里面用这种方法总的时间复杂度会到O(n^2),考虑到n的大小,这种方法显然是行不通的。有没有更为快速,可能有人想到使用堆,这也是优先队列使用的方法,如果实现的好的话,可以把时间复杂度从O(n)降到O(logn),不过,我这里说的不是这种方法,我要来说一下时间复杂度为O(1)的一种... 阅读全文
posted @ 2013-08-04 19:02 xindoo 阅读(184) 评论(0) 推荐(0)
摘要:题意就是让你求区间最大和最小值的差值。这题可以用线段树,也可以用Tarjan 的Sparse Table算法(参考刘汝佳训练指南197),这里我用了ST算法,还有要说明的是题目描述的数据范围是不准确的如果你数组开比50000大一点点的话是会RE的。代码://poj 3263 RMQ//2013-07-30-21.39#include #include #include using namespace std;const int maxn = 100005;int dmax[maxn][30];int dmin[maxn][30];int a[maxn];void init(int n){ .. 阅读全文
posted @ 2013-07-30 21:45 xindoo 阅读(199) 评论(0) 推荐(0)
摘要:题目链接 这两个题目是一样的,大概题意是有3个操作 add x, 在集合中加入x, del x 是删除x, sum 是求出由小到大排序后所有下标mod5等于3的数的和。 这个在hdoj上面,这个题给的时间比较多10s,我用了stl 里的vector和lower_bound, lower_bound 它的作用是返回不小于x的第一个数的位置,这样我们每次插入后就能保证他有序。 最终耗时6234MS,而这种方法在codeforces上超时了,cf只给了3000ms,这道题的标准做法是用线段树。先给出stl的做法//2013-05-18-20.17// hdoj 4288 cf 85d#include 阅读全文
posted @ 2013-05-18 20:38 xindoo 阅读(185) 评论(0) 推荐(0)
摘要:题目链接 题目很长,看加猜加谷歌翻译才看懂了题目。每级台阶的宽都是1,但高不同,并且告诉你了,然后给你m个箱子,长和宽都告诉你,把箱子靠左放,求箱子的底部有多高。 因为都是放在最左边的,所以只要和最左边的高度比较,这样就不用更新线段树了。代码://cf 272 C//2013-05-14-20.26#include using namespace std;const int maxn = 100005;struct node{ int l, r, mid; __int64 m;}tree[maxn b) return a; return b;}void bui... 阅读全文
posted @ 2013-05-14 20:28 xindoo 阅读(201) 评论(0) 推荐(0)
摘要:题目链接题意: 给你一个字符串,在字符串尾部加上一些字符,使这个字符串变成一个回文串(正反读都一样的字符串),求该回文串的最小长度。思路: 在light oj里这个题目是属于KMP分类的,但乍看好像不是kmp,因为只有一个字符串。要想的到一个回文串,把该字符串翻转接到原串后面必然是一个回文串,但并不一定是最短的。我们必须考虑怎么把两个串尽量融合在一起,这就要看翻转串的前段与原串的后段有多少是匹配的了,这里就用到了KMP算法。代码://2013-05-13-20.01#include #include const int maxn = 1000005;char a[maxn];char b[.. 阅读全文
posted @ 2013-05-13 20:10 xindoo 阅读(125) 评论(0) 推荐(0)
摘要:题目链接 逆序的概念大家都知道,一个数到逆序数就是该数左边大于它到数的个数。 很多没学过数据结构的人一上来肯定就是一个个数了,看看数据量500k,显然这种暴力的方法是行不通的。 我们换种想法,可以在输入过程中对每个数的逆序数求解,建一个vis数组(初始化为0),只要输入一个数,在它的位置标记为1,然后计算出它的左边一共有多少数被标记了就可以知道多少个数比他小了,当然逆序数也就知道了,求从左到右数的和,这是树状数组最擅长的了。 但我们看看每个数的范围是0 ≤ a[i] ≤ 999,999,999,我们不可能开那么大的数组,即使开的了也会浪费很多,这个时候我们就要对数据进行离散化处... 阅读全文
posted @ 2013-04-25 16:09 xindoo 阅读(188) 评论(0) 推荐(0)
摘要:并查集小结并查集大体分为三个:普通的并查集,带种类的并查集,扩展的并查集(主要是必须指定合并时的父子关系,或者统计一些数据,比如此集合内的元素数目。)POJ-1182经典的种类并查集POJ-1308用并查集来判断一棵树。。注意空树也是树,死人也是人。POJ-1611裸地水并查集POJ-1703种类并查集POJ-1988看上去似乎和种类并查集无关,但其实仔细想想,就是种类并查集。。。只不过是种类数目无穷大,通过合并,可以确定两个物品之间的种类差(即高度差)POJ-2236裸地并查集,小加一点计算几何POJ-2492裸地种类并查集POJ-2524又是裸地并查集POJ-1456常规思想是贪心+堆优化 阅读全文
posted @ 2013-04-24 11:36 xindoo 阅读(119) 评论(0) 推荐(0)
摘要:先放一张图片对4 5 2 8 7 6 1 3 分别建划分树和归并树划分树如下图红色的点是此节点中被划分到左子树的点。 我们一般用一个结构体数组来保存每个节点,和线段树不同的是,线段树每个节点值保存一段的起始位置和结束位置,而在划分树和递归树中,每个节点的每个元素都是要保存的。为了直观些,我们可以定义一个结构体数组,一个结构体中保存的是一层的元素和到某个节点进入左子树的元素的个数,不同于线段树,我们不能保存一个节点的起始结尾位置,因为随层数的增加,虽然每个结构体保存的元素数目是一定的,但随层数的增加,元素早已被划分到不同的子树中了,而且这数目是指数增加的。 那我们如何确定一个子树的边界?... 阅读全文
posted @ 2013-04-16 21:24 xindoo 阅读(550) 评论(0) 推荐(0)
摘要:题意: 有n个数,有m组操作,1 i表示将第i个数先输出,然后置0, 2 i v 表示给第i个数加上v, 3 i j 表示求i 到 j 的和,注意,这里数组是从0开始的,而我们构造的树状数组是从1开始的,使用在程序中要进行一定的处理。//LA 1112 - Curious Robin Hood(树状数组)//2013-04-13-08.22#include #include const int maxn = 100010;int a[maxn], b[maxn];int n;int lowbit(int x){ return x&(-x);}void update(int x, int 阅读全文
posted @ 2013-04-13 00:23 xindoo 阅读(152) 评论(0) 推荐(0)
摘要:题目链接题意: 有一字符串只包含0和1,然后又m组操作,I L R是将从L到R的字符进行翻转操作0变为1、1变为0,Q x表示询问第x的字符。思路: 我们只需要计算对询问的字符进行了多少次翻转,如果是偶数次,该字符变,否则翻转。对于区间的更新,我们可以使用线段树,不过对于这个题,因为只是对点的查询,而且每个节点的初始值都相同,为0,因此我们可以直接使用树状数组。下面是一个很巧妙的做法,而且很容易理解。用了树状数组的区间更新 单点查找(一般为单点更新 区间查找)例如 区间(2,4)加1则Updata(2,1) Updata(4+1,-1)实现了更新(2,4)的值而不改变其他值求Sum时即可得.. 阅读全文
posted @ 2013-04-12 18:58 xindoo 阅读(195) 评论(0) 推荐(0)
摘要:题目链接线段树解法#include #include using namespace std;const int maxn = 100010;struct node{ int l, r, mid, minn;}tree[maxn> 1; tree[o].mid = m; if (l == r) { tree[o].minn = a[l]; return ; } build(l, m, o tree[o].mid) return query(l, r, (o#include using namespace std;co... 阅读全文
posted @ 2013-04-12 13:24 xindoo 阅读(161) 评论(0) 推荐(0)