luogu P5290 [十二省联考2019]春节十二响
做题千万条,读题第一条
编程不规范,爆零两行泪
推荐阅读(雾)
考虑一个贪心,就是先把所有点按权值从大到小排序,然后每次考虑能不能和其他已经插进去的点放在一个集合,不能那么答案就加上对应权值.如果我们按照最优策略构造,那么最后首先集合个数是最少的,而且因为尽量把大的元素和更大的放在一起,那么最终答案也是最优的
这个贪心怎么优化呢?注意到两个点可以在一起选,当且仅当这两个点的子树的\(dfn\)序区间无交,那么每次选点的过程中,如果所有集合都和他无交,那么可以放在其他集合中,否则就必须新开一个集合.那如果加一个点就在对应区间+1,考虑当前这个区间的最大值,他代表有几个集合和当前区间有交,所以如果区间最大值为当前集合个数就要新开一个集合,那么要更新答案.这个可以线段树区间加,区间最大值实现
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db double
using namespace std;
const int N=2e5+10;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
void add(int x,int y)
{
++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
}
int n,a[N],dfn[N],ti,sz[N];
void dfs(int x)
{
sz[x]=1,dfn[x]=++ti;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
dfs(y),sz[x]+=sz[y];
}
}
struct node
{
int l,r,x;
bool operator < (const node &bb) const {return x>bb.x;}
}qq[N];
int ma[N<<2],tg[N<<2];
#define mid ((l+r)>>1)
void psup(int o){ma[o]=max(ma[o<<1],ma[o<<1|1]);}
void ad(int o,int x){ma[o]+=x,tg[o]+=x;}
void psdn(int o){if(tg[o]) ad(o<<1,tg[o]),ad(o<<1|1,tg[o]),tg[o]=0;}
void modif(int o,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr){ad(o,1);return;}
psdn(o);
if(ll<=mid) modif(o<<1,l,mid,ll,rr);
if(rr>mid) modif(o<<1|1,mid+1,r,ll,rr);
psup(o);
}
int quer(int o,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr) return ma[o];
psdn(o);
int an=0;
if(ll<=mid) an=max(an,quer(o<<1,l,mid,ll,rr));
if(rr>mid) an=max(an,quer(o<<1|1,mid+1,r,ll,rr));
psup(o);
return an;
}
LL cn,ans;
int main()
{
n=rd();
for(int i=1;i<=n;++i) a[i]=rd();
for(int i=2;i<=n;++i) add(rd(),i);
dfs(1);
for(int i=1;i<=n;++i) qq[i]=(node){dfn[i],dfn[i]+sz[i]-1,a[i]};
sort(qq+1,qq+n+1);
for(int i=1;i<=n;++i)
{
int ll=qq[i].l,rr=qq[i].r;
if(quer(1,1,n,ll,rr)>=cn) ++cn,ans+=qq[i].x;
modif(1,1,n,ll,rr);
}
printf("%lld\n",ans);
return 0;
}