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)$