上一页 1 ··· 30 31 32 33 34 35 36 37 38 ··· 85 下一页
  2012年4月2日
摘要: POJ_3017 这个题目动规的方程是很好写出来的f[i]=min{f[j]+max[j+1,i]},其中j要满足sum[j+1,i]<=M。 如果裸着做的话显然是O(N^2)的复杂度,而动规的维数显然是一维,不能再减了,于是我们要试图减少决策的数量,换句话说对于每个i,我们要在O(1)或者O(logN)或者同级别的时间复杂度内找到最优的决策(decision)j,直接令f[i]=f[j]+max[j+1,i]。 先不说别的,这个max要怎么求呢?RMQ问题固然可以预处理出来,但实际上没必要那么麻烦,我们可以维护一个单调队列,对于当前的a[i],先将队尾小于或等于a[i]的元素删掉,再把 阅读全文
posted @ 2012-04-02 13:12 Staginner 阅读(2077) 评论(4) 推荐(3) 编辑
摘要: POJ_3580 更多splay练手的题目可以参考胡浩的博客http://www.notonlysuccess.com/index.php/splay-tree/,有了前面对区间翻转、切割的训练之后,这个题目就显得思路比较直观了。 对于ADD操作,和线段树的处理是一样的,加一个add延迟标记即可,在pushdown的时候别忘记还会影响到子树上记录的min值就OK了。 对于REVERSE操作,用一个rev延迟标记即可,注意到pushdown的时候子树中rev的标记应该是加1模2,而不能简单的赋值成1就OK了。 对于REVOLVE操作,实际上相当于把一个区间挪到了另一个区间后面,于是先把要移动的. 阅读全文
posted @ 2012-04-02 00:43 Staginner 阅读(535) 评论(1) 推荐(1) 编辑
  2012年4月1日
摘要: HDU_3487 拿这个题目练了一下splay的区间的切割,也就是删除、移动、添加一个连续的区间。#include<stdio.h>#include<string.h>#define MAXD 300010int N, M, T, node, size[MAXD], rev[MAXD], left[MAXD], right[MAXD], pre[MAXD], key[MAXD], ans[MAXD], P;void newnode(int &cur, int k){ cur = ++ node; key[cur] = k; size[cur] = 1; rev[ 阅读全文
posted @ 2012-04-01 18:38 Staginner 阅读(393) 评论(0) 推荐(0) 编辑
摘要: HDU_3436 这个题目无论用什么方法做,首先离散化时候一定要处理好,否则后面会越想越乱。一个比较好的离散化的思路就是把需要Top和Query点看成一个小区间,然后把这些点之间的部分,以及头尾两个部分看成其他的一个一个的区间。 线段树或者树状数组的做法可以参考http://www.cppblog.com/Yuan/archive/2010/08/18/123871.html,我就只说一下用splay的思路吧。维护splay只需要维护一个size,但这个size表示的不是子树的节点数,而是子树上的所有区间所包含的点的总数。 对于top操作,由于我们要先找到那个点(或者说是小区间)的节点标号(. 阅读全文
posted @ 2012-04-01 17:08 Staginner 阅读(732) 评论(0) 推荐(1) 编辑
摘要: HDU_1890 第一次写涉及到区间翻转的splay,结果就没注意到翻转的操作类似于线段树中对区间0、1取反的操作,下传标记的时候记录翻转的标记rev应该是加1模2,而不能简单地将左右儿子的rev置为1。 下面说说具体的思路吧。 我们每次可以先将“最小”的点旋转到根,那么根左边的区间自然就是要翻转的区间了,于是我们对根左边的区间打上翻转的标记,然后将根删除,如此反复N-1遍。对于每次要输出的值,假设我们现在试图令第i个block到位,那么把这个点旋转到根后,输出i+size[left[T]]即可,其中T表示根。当然,最后还要输出一个N。 然而,我们要如何知道每次该旋转哪个block呢?即便.. 阅读全文
posted @ 2012-04-01 01:17 Staginner 阅读(1540) 评论(0) 推荐(0) 编辑
  2012年3月31日
摘要: SPOJ_704 这个题目可以用AC自动机(其实应该说是trie图)+dp去做。 我们可以把问题等效成从X这个字符串里面挑出一些字符组成一个新的字符串,并且新的字符串中不能包含Y。我们可以把生成字符串的过程模拟成在trie图上行走的过程,则第i步时就会有两种选择,要么走到X[i]这个字符上,要么停留在原地,其中停留在原地就相当于把X[i]这个字符删掉了,因此代价应该增加1。为了保留第i步走到第j个点时的最小代价,可以用f[i][j]记录,当然空间可以优化成一维的。 最后我们把行走了len[X]步后的到达各个节点的最小代价统计一下,输出最小值即可。#include<stdio.h># 阅读全文
posted @ 2012-03-31 15:39 Staginner 阅读(438) 评论(0) 推荐(0) 编辑
摘要: POJ_2528 首先说明一点,直接离散化海报的端点是不行的,因为这样会默认把海报范围内的所有端点都覆盖掉后就算把海报覆盖了,然而实际上是不可以这样判断的。比如1 10、1 4、6 10这三张海报,尽管最后1、4、6、10都被覆盖了,但是5这个单位线段是没有被覆盖的,所以应该输出3。 为了避免上述的问题,我们在离散的话的时候可以选择将区间离散化,海报的端点算作一个区间,相邻两个端点之间也算所一个区间,那么上面的例子就被离散化成了1 1、2 3、4 4、5 5、6 6、7 9、10 10这样几个区间,还有更方便一点的做法,就是不去离散化区间,但是添加上海报端点左边的点,对于上面的例子离散化之.. 阅读全文
posted @ 2012-03-31 13:38 Staginner 阅读(191) 评论(0) 推荐(0) 编辑
摘要: HDU_2871 胡浩的博客上说这个可以做splay的热身题,结果写出来洋洋洒洒270行代码却落得TLE收场,不得不改成线段树去写了。 reset操作是最简单的,直接将根初始化并加个延迟标记即可。 我们可以用lc[](left contiguous)表示一个区间从左边开始连续有多少个空位,rc[](right contiguous)表示一个区间从右边开始连续有多少个空位,mc(max contiguous)表示这个区间内最长的连续的空位。有了这三个数组我们就可以很方便地实现New操作了。 对于Free操作,知道这个点是否是空位是很简单的,但为了获得Memory unit的左、右端点,我们... 阅读全文
posted @ 2012-03-31 02:29 Staginner 阅读(675) 评论(0) 推荐(1) 编辑
  2012年3月30日
摘要: POJ_2892 这个题目用splay去想还是比较直接的,但之所以感觉思路比较直接,也是因为前面又巩固、学习了一下线段树的一些对于区间合并的操作,更多的涉及线段树区间合并的题目可以参考胡浩的博客http://www.notonlysuccess.com/index.php/segment-tree-complete/。 当然,这个题目是可以用线段树去做的,而且和splay去做是比较相似的,查询的时候都是去找这个点左半部分区间的右边有多少个连续的1,以及这个点右半部分区间的左边有多少个连续的1。 下面还是说一下我用splay做的时候的一些思路吧。 首先要明确的就是splay上一个节点表示... 阅读全文
posted @ 2012-03-30 16:27 Staginner 阅读(312) 评论(0) 推荐(0) 编辑
摘要: HDU_3397 感觉这种维护序列的题目就是填代码,把每种操作的模块写好就OK了。更多和区间合并相关的问题可以参考胡浩的博客http://www.notonlysuccess.com/index.php/segment-tree-complete/。 为了方便实现各种操作,可以引入lc[0/1](left contiguous)表示一个区间从左边开始连续最长0/1是多少,rc[0/1](right contiguous)表示一个区间从右边开始连续最长的区间0/1是多少,mc[0/1](max contiguous)表示当前区间最长的0/1是多少,num[0/1]表示当前区间的0/1的数量是多少 阅读全文
posted @ 2012-03-30 13:39 Staginner 阅读(232) 评论(0) 推荐(0) 编辑
上一页 1 ··· 30 31 32 33 34 35 36 37 38 ··· 85 下一页