[ZYOI Round1] Bird/鸟 题解
神说,笛卡尔树秒了
如果不知道笛卡尔树的,可以去 OIwiki 里了解一下。接下来的讲解将依照笛卡尔树展开。
这是一种理解起来很方便,虽然不怎么常用的构造树,复杂度是
解题思路
OK,想必你已经大致了解了笛卡尔树是什么东西。
由题可得,设
我们观察题目不难发现,对于任意一棵树,想要飞的最多,下一步应该飞到这棵树左侧或右侧可到达的最高的树,因为左侧或右侧其它的树都可以通过这棵树飞到。
因此,我们可以构建一个大根的笛卡尔树。对于每一个节点,它的左儿子和右儿子即它左边和右边最大的那个节点。
接着我们依据公式
最后,依据
特别地,对于左右儿子节点与本节点相同的情况,根据题目与解法推理可得,只需要不记录相同的儿子节点即可(就是
时间复杂度的大头反而是排序,其余都是
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N=3e5+5;
int n,k,ans;
int b[N],cot[N];
int rs[N],ls[N],sta[N],top,root;
struct str{
int num,sum;
}a[N];
bool cmp(int x,int y){ return x>y; }
bool cmp2(str x,str y){ return x.sum>y.sum; }
int solve(int p)
{
if(p==0)
return 0;
if(a[ls[p]].num==a[p].num)//左右儿子节点相同的情况
a[p].sum=max(a[p].sum,solve(ls[p]));
else
a[p].sum=max(a[p].sum,solve(ls[p])+1);
if(a[rs[p]].num==a[p].num)
a[p].sum=max(a[p].sum,solve(rs[p]));
else
a[p].sum=max(a[p].sum,solve(rs[p])+1);
return a[p].sum;
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i].num;
if(a[i].num>a[root].num)
root=i;
}
for(int i=1;i<=k;i++)
cin>>b[i];
sort(b+1,b+1+n,cmp);
//构建笛卡尔树
for(int i=1;i<=n;i++)
{
int p=top;
while(a[i].num>a[sta[p]].num && p>0) p--;
if(p>0) rs[sta[p]]=i;
if(p<top) ls[i]=sta[p+1];
sta[++p]=i;
top=p;
}
//搜索求sum
solve(root);
ans+=a[1].sum-1;//记得要减 1
sort(a+1,a+1+n,cmp2);
top=1;
for(int i=1;i<=n;i++)
{
while(b[top]>=a[i].num && top<=k)
{
ans+=a[i].sum-1;
top++;
}
}
cout<<ans;
return 0;
}
求过。
想过审好难啊QWQ。