POJ3368区间最值-ST算法

题目解答

这是一道可以使用线段树轻松解决的问题,只要维护总最长区间,从左边开始和右边开始的最长区间三个域即可。

但是,还有更巧妙的RMQ解法,假如我们只要[1,n]的最长区间,很显然只要预处理一下,把连续的值的频率算出来,就可以很简单的RMQ了,但问题是:如果区间断开了,那么RMQ是否就失效了?对于断开的区间的整体来说必定是这样,但是其中的完整的子段依然保留着RMQ的最优性。

例如:-1 -1 1 1 1 1 3 10 10 10,预处理后:1 2 1 2 3 4 1 1 2 3,如果查询[5,10]直接ST会算出4,但是应该是3,再仔细观察,因为数列非递减,所以只有左边断开才会影响结果,因此我们只要特殊处理一下左边的连续值即可。然后对剩下的使用ST解决。

Read More

POJ2104归并树

题目解答

使用线段树的划分结构维护归并排序,线段树是虚的,不需要建立出来。查找时,大体分为三次:首先二分总区间的中值 -> 接着使用已经建好的归并树二分中值在待查区间的排位(需要两个小的二分组成) -> 若与待查排位一致就输出,否则总区间折半继续上述步骤直到找到。

本题目实现以后,我从一个神人的Blog发现了使用 STL 优化的方法:查待查区间的排位可以用STL。(冬令营上说可以使用)

我原本的程序:长61Lines | 运行时间::3.4s;
使用STL后的程序:长56Lines | 运行时间::2.4s; <– OTL

Read More

NOI2000青蛙过河

题目解答

这道题目是一道好题,因为可以从多个角度出发考虑,途径很多。首先,乍一看题貌似是Hanoi塔的模式,只不过增加了特定的限制(不可以向回走),先分析一个例子:石墩有2个,荷叶3个的情况。这种情况可以有至多16只青蛙过河。首先有4只先到一号石墩,接着另有4个号码较大的到达2号墩,这是很容易做到的,然后让1号墩上的3个小的跳到荷叶上,1号墩剩下那只直接跳到2号,3个荷叶上的再跳到2号。此时2号墩已经饱和了(推一下即可知道),而1号和荷叶是空的让其饱和,则可再次有7只青蛙,此时已经有15只青蛙。左岸的第16只可以直接跳到右岸,而且可以发现怎样跳过来还可以怎样跳回去,只不过我们不跳到左岸而是右岸,这是对称的。因此可以有16只。

NOI 2000

事实上,我们仔细分析可以发现,只有荷叶的话,那么最多只能有荷叶数加1只青蛙可以过河,因为过河顺序是单向传递的。所以我们如果想使过河数最大可以令青蛙在河中央停留的只数达到最多,这样只有荷叶的话必然是荷叶数加1只青蛙可以渡过。但是存在石墩就不一样了。因为石墩上可以有多只编号严格递减的青蛙。首先荷叶可以作为跳板,并由这些跳板使多只青蛙到达河中的石墩,并且尽量可以积累的多一些。而且河中的石墩是无所谓顺序的,所以我们可以这样来看待问题:

把左岸,河中央,右岸分为3个阶段。把河中的石墩当作目的地,用样例来说:根据前面的分析,1号石墩可以有4只青蛙,2号同样可以有4只,此时1、2号石墩的青蛙序号严格递减,所以1号的青蛙又可以看作右岸借助荷叶到达2号石墩。2号就有8只。此时因为2号石墩的青蛙数的总数比荷叶石墩的总数还多,所以2号石墩已经饱和。1号已空,再重复之前的工作……如此反复进行:i号石墩总可以包含(i-1)号,即以1号石墩的青蛙作为单位青蛙数s,会有s,2 * s,4 * s……只,所以总共会有2^h*(k+1)个青蛙可以过河。得到通项公式。

Read More

NOI2007项链工厂

题目解答

(这道题目好像很流行 (^o^))。分析题目,因为所有操作均是在区间内完成的,因此可以使用线段树,保证维护的摊还时间限定在O(logn)以内,但是本题的难点不在线段树本身,而是对于Flip和 Rotate的维护,这是其一,其二就是如何合并两棵树。针对这个问题,通过分析我们知道,珠子之间的相对位置固定,这样就可以使用偏移量来记录,再用bool的标志记录是否偏转,具体的计算请看我的程序的hash()函数,这样就解决了这两个问题。而子树合并,则要再维护rcol,lcol两个分别代表左右端点的域。这样的好处,相信不用我再说了。

Read More

USACO 3.4.2 Heritage

题目解答

分治策略:首先根据常识凡是中序+前序,中序+后序均可确定唯一二叉树。前序+后序不可确定。因此我们根据中序+前序先构造出二叉树,然后输出即可。构造方法是:因为前序遍历的第一个一定是根,那么接着找到根在中序遍历的位置。在中序遍历中左边的就是左子树。右边的就是右子树。然后下放左右子树和相应的前序遍历接着做,直到没有左右子树为止。(如图)

Read More

POJ3667线段树

题目解答

裸的线段树,线段树能解决的问题很多,这道题目是非常典型的线段染色问题。有三种状态,无色(空),满色(有人),杂色。主要考察的也就是实现线段树的惰性,即懒操作。修改颜色时不是一改到底的,在适当粒度的区间做好标记,当出现更细粒度(小于某个区间)的操作时再下放。例如:区间[1,10]标记为客满,同时区间[1,2]标记为空是可以在某些时刻共存的,想想为什么。

Read More

USACO 3.1.4 Rect1

题目解答

刚一读题,第一反应就是朴素染色,但是因为较大的数据,染色法绝对行不通。因为我们没有必要重复覆盖某个点,包括计算面积我们不需要统计,而是直接用坐标计算。所以可以考虑使用面向矩形整体的方法:

  1. 二维线段树或者离散化 + 线段树:这种方法的弊端是要么过于复杂,要么MLE,所以牛刀还是用来屠牛吧
  2. 我具体论述一下矩形切割:首先通过分析我们知道凡是在后面覆盖过的绝对不会被前面的覆盖,因此假设我们覆盖第N个矩形,那么第(N-1)个一定在它的下面,由此知道要倒序染色(1),这样可以省去很多的操作;而两个矩形相交如何处理呢?我们知道:如果两个矩形相交,他们的交集必定是一个矩形,记录一个矩形只需两个对角坐标,处理方便,所以我们要对每次的覆盖进行切割(2);

Read More

NOI2004郁闷的出纳员

题目解答

这是一道考察数据结构的题目,理论上使用静态的会更好,不见得动态的就快,但是我是使用Treap AC的。原理很简单,就是需要额外再用一个delta来记录差量,避免Treap退化,所以在加入一个节点时 ,要减去这个差量,最后输出时加上即可。然后’S’、’A’操作只改变delta,剩下的就是实现了。

Read More

USACO 2.3.3 Cowtour

题目解答

这道题目是图论问题,首先用floyd求出每对点的最短路,然后再找出单独每个点的可连接的最远的点(直径),接下来就是计算两个分离牧区的直径。首先遍历所有不连通的点对,然后用这两点的距离加上两点原来的直径。如果更小,则更新直到结束。
但是还有一种特殊情况:“包含”。如果一个牧场恰好包含另一个,且大的牧场直径比计算出的要长一些,则结果应该是更大的那个才对。(参考图片:红色表示最终连接的结果,蓝色表示大牧场的直径,显然蓝色的才正确)

Read More

NOIP2001Car的旅行路线

题目解答

新年第一题:这道题目很值得一说,首先这是一个比较典型的计算几何转化为图论去做,同时也是需要结合两者的不错的题目。大体思想是首先用向量法计算出第4个点,因为第4个点是现有的3个点中的作为现有RT三角形的一个对角点,所以先要确定直角点,用点积为0判定,剩下的很简单了。接着要建模为一张图,然后计算最短路径。大体就是这样。

关于计算最短路径:我的想法是先求出所有点对的最短路径,然后遍历A市与B市的飞机场选出一个最短的,但是这样似乎麻烦而且时效低,所以我介绍一下官方的强大方法:首先对于A市和B市,把他们的铁路价格都改为0,这样无论选择两个城市中的哪个机场,都不用额外花费铁路价格,把城市封装为一个整体,意味着A、B的机场任意。做一遍Dijkstra即可。

Read More