gmoj 6816. 【2020.10.06提高组模拟】随机的排列

题目https://gmoj.net/senior/#main/show/6816题解发现如果对原序列建一棵笛卡尔树,一个节点x在原图中连向的点其实就是它在笛卡尔树上的左子树的右链+右子树的左链,如下图。
摘要由CSDN通过智能技术生成

题目

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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值