题目
https://gmoj.net/senior/#main/show/6816
题解
发现如果对原序列建一棵笛卡尔树,一个节点x在原图中连向的点其实就是它在笛卡尔树上的左子树的右链+右子树的左链,如下图。
有了这个性质就很好弄了,这样子一棵子树的可能被祖先覆盖的部分就是它自己 以及左子树的左链 和右子树的右链。
因此设 f i , 0 / 1 , 0 / 1 , 0 / 1 f_{i,0/1,0/1,0/1} fi,0/1,0/1,0/1表示以 i 为根的子树中,点 i 、左子树的左链、右子树的右链 是/否被覆盖,其它节点都已经被覆盖的最少关键点数量,转移不难。
至于交换操作,不妨设 p x < p x + 1 p_x<p_{x+1} px<px+1,那么x必定在以x+1为根的子树的左子树右链的尽头上。用x的左儿子代替x(没有就直接删去x),然后把x插入以x+1为根的子树的右子树的左链某个位置上,接着把这个位置上的点变成自己的右儿子就好了。这时只用修改x原来的位置和现在的位置到根的两条路径上的 f 值就好了。因为数据是随机的,笛卡尔树深度是log的,因此能过。
CODE
#include<cstdio>
using namespace std;
#define N 100005
int a[N],lson[N],rson[N],fa[N],f[N][2][2][2];
inline void read(int &x)
{
char ch;
while(ch=getchar(),ch<'0'||ch>'9');x=ch-48;
while(ch=getchar(),ch>='0'&&ch<='9') x=x*10+ch-48;
}
inline void calc(int k)
{
f[k][0][0][0]=f[lson[k]][0][0][1]+f[rson[k]][0][1][0];
f[k][0][1][0]=f[lson[k]][1][1][1]+f[rson[k]][0][1][0];
f[k][0][0][1]=f[lson[k]][0][0][1