今天的题原来是COCI的……LOJ上有。
总结
今天我被打爆了。
首先读完题,哇塞,怎么这么多树上的题目?!!
T4看起来很可做,估计要么就是单调栈+线段树,要么就是分治。
本来脑子一热就要开打第一种方法了,但是仔细想了想,好像不能这样做。
后来实在想不到怎么做,我突然想到如果数据比较水,单调栈是 O(nlog2n)O(n\log_2 n)O(nlog2n) 的,于是就想这样子水分。
接着再看了看前三题,觉得T1较为可做。显然最优的方案是每次删除权值最大的那个点的所有出边。但是怎么维护这些出边的另一端的最大值呢?没想出来。
我跳到了T2,考虑当前我们要删掉结点 x,yx,yx,y 和它们父亲之间的边,固定 xxx ,可以发现 yyy 是除以 xxx 为根的子树外的连通块的重心的重儿子(不考虑 yyy 是 xxx 的祖先的情况)。
那现在就要动态维护重心了。其实可以发现 xxx 向下走时,重心会向 xxx 靠近;xxx 向上走时,重心就会远离 xxx 。这样应该可以做。但由于只剩下一个多小时,就弃了。
T3的部分分看起来很不可做……
再看回T1,突然有了些想法:
考虑当一个点被删除时,若以它为根,它的每个子树中最大的点都会被计算一次。
接着脑子一抽,得出结论:
一个点被计算的次数等于以它为根时子树中存在比它大的点的儿子的数量。
于是我很愉快地打了换根DP,又很愉快地炸了。
T4我枚举左端点 iii,发现当 a,ba,ba,b 不变时,右端点 rrr 越大越好。于是就在两个单调栈上面乱搞。但因为我忽略了单调栈上的一个点和它的上一个点在原序列上的位置之间也会存在比它小的点(其实那些点只是比上一个点小罢了)这一性质,就挂了。
最后:40+50+0+0=9040+50+0+0=9040+50+0+0=90
总结:
- 打代码前一定要好好想想自己的想法有没有问题,打着打着才发现自己的做法挂了就很亏了;
- 尽可能早点开始打代码,最好 9:309:309:30 左右开始;
- 我的思维还不够灵活,如T1从删边角度想不出来就应该考虑加边。
题解
T1
解法一
考虑加边,设 u,vu,vu,v 表示边 (x,y)(x,y)(x,y) 端点所在的连通块,那么最优的方案就是每次加上 maxi∈uti+maxi∈vti\max_{i\in u}t_i+\max_{i\in v}t_imaxi∈uti+maxi∈vti 最小的块。
解法二
每次删边时,权值较大的那个端点肯定是会被统计到一次的;考虑另外一边,发现一个点作为这一边的子树的最大值被算了一次后,下一次就会轮到它被删。因此答案就是∑i=1nti−maxi=1nti+∑i=1n−1max(txi,tyi)\begin{aligned}\sum_{i=1}^n t_i - \max_{i=1}^n t_i +\sum_{i=1}^{n-1} \max(t_{x_i},t_{y_i})\end{aligned}i=1∑nti−i=1maxnti+i=1∑n−1max(txi,tyi)
T2
可以用倍增求出 xxx 的祖先中最合适的 yyy ,在递归完这个点后把它的 sizsizsiz 放进权值线段树中,作为合适的兄弟 yyy 对其它 xxx 造成贡献。
T3
这题很显然是DP,但是难在怎么DP。
可以发现如果我们从一个点往下走一条长链再走回去,是等价于在这一条链的每一个要往下走的点处往下走一步再往上走一步。
那么就可以DP了。设 fi,0/1/2,0/1f_{i,0/1/2,0/1}fi,0/1/2,0/1 表示当前序列的最后一个数是 iii ,没有经过起点或终点、经过起点或终点中的一个、经过它们两个,现在 iii 的颜色是 0/10/10/1 。
转移可以由第二维的 0→0,1,2;1→1,2;2→20\to 0,1,2;1\to 1,2;2\to 20→0,1,2;1→1,2;2→2 ,转移时可以在 iii 和儿子之间往返一次,也可以在 iii 和儿子之间往返两次。
注意,0→10\to 10→1 要造成1的代价,1→21\to 21→2 不会造成代价。
T4
真的是分治。