模拟测试50

T1:

  考虑什么时候增加高度对答案有贡献。

  可以发现,当一个建筑物两侧的建筑高度均大于它时(边界除外),才会有贡献。

  所以我们可以先暴力找出所有当前有贡献的区间,压入队列,一个一个处理。

  尝试将一个区间内的建筑物增高,我们发现,对于每个建筑物,每次增加的代价是等差数列的形式。

  将平方差分得到:1,3,5,7......。

  于是我们只要知道增高最下面一层需要的代价,就能算出增加任意高度的代价,这个值初始时均为一,把它存放在b数组里。

  然的后考虑增加一段区间,只有这个区间中所有建筑物的高度相等,且两侧建筑物高度更高,这个区间才能被考虑。

  增加一段区间的高度,每次增加的代价不断升高,而每次的贡献不变,所以增加到代价等于贡献是最优的。

  这个值可以O(1)算出,也可以二分。

  每次动态更新b数组,如果当前区间被填满,就尝试左右扩展区间,同时累加新加入点的b数组作为代价。

  如果当前区间不被填满,扩展到新区间贡献不会增加,而代价反而增加了,所以他一定不是更优的。  

  持续这一过程直到队列为空即可。

  时间复杂度$O(n)$

T2:

  统计二维区间内点对个数。

  是典型的四维偏序,可以树套树套树......

  然而可以二维莫队A掉。

  时间复杂度$O(qn sqrt{n})$,真实复杂度O(莫队)。

T3:

  树上直径问题。

  可以先两次DFS求出整棵树的直径。

  然后分别以直径两端点为根做一次树形DP,求出每棵子树内的直径。

  对于没在直径上的点,也做一次类似过程。

  枚举断边,如果断边在直径上,那么就可以用DP值求出新树的最小直径;

  如果不在直径上,就用原树直径和离直径远的点所在的子数的直径更新。

  新直径求法:

    设$l_1$和$l_2$分别为两个连通块的直径,$l$为新树的最小直径。

    $l=max(l_1,l_2,lceil frac{l_1}{2} ceil + lceil frac{l_2}{2} ceil +1)$

  连边一定连的是两个连通块直径的中点,DFS后用深度数组找出来即可。

  时间复杂度$O(n)$

原文地址:https://www.cnblogs.com/hz-Rockstar/p/11572852.html