LOJ传送门
洛谷传送门
BZOJ传送门
解析;
来给大家看一个 O ( n log 2 n ) O(n\log ^2n) O(nlog2n)的菜鸡做法。
考场上 y y yy yy出来的。
来看一个正确性显然的贪心:
首先我们在当前没有选择的点中选出代价最大的点,将它的掌控范围,即它到根的链和它的子树,全部ban掉,即本轮禁选。将它的权值加入答案。
然后再在没有ban掉的点中,找到权值最大的点,ban掉掌控范围,但是权值不用加入答案了。
直到没有点可以选择,退出本轮,将所有ban掉的点恢复,并将已经选择了的点的权值设置为 0 0 0,如果所有点全部已经选择,退出,不然进入下一轮。
显然可以直接上树剖和线段树维护这个过程。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
using std::cout;
using std::cerr;
typedef std::pair<int,int> pii;
#define mp std::make_pair
#define fi first
#define se second
cs int N=2e5+5;
ll ans;
int n,val[N];
int last[N],nxt[N],to[N],ecnt;
inline void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
}
int fa[N],siz[N],son[N],top[N],dep[N];
int in[N],out[N],pos[N],dfs_clock;
void dfs1(int u){
siz[u]=1;
for(re int e=last[u],v=to[e];e;v=to[e=nxt[e]]){
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u){
pos[in[u]=++dfs_clock]=u;
if(son[u]){
top[son[u]]=top[u];
dfs2(son[u]);
}
for(re int e=last[u],v=to[e];e;v=to[e=nxt[e]])if(v!=son[u]){
top[v]=v;
dfs2(v);
}
out[u]=dfs_clock;
}
pii mx[N<<2];
bool ban[N<<2],need[N<<2];
bool used[N];
inline void pushup(int k){
mx[k]=std::max(mx[k<<1],mx[k<<1|1]);
need[k]=ban[k]||need[k<<1]||need[k<<1|1];
}
inline void build(int k,int l,int r){
if(l==r){
mx[k]=mp(val[pos[l]],l);
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
inline void modify_ban(int k,int l,int r,cs int &ql,cs int &qr){
if(ban[k])return ;
if(ql<=l&&r<=qr){
mx[k]=mp(0,0);
ban[k]=need[k]=true;
return ;
}
int mid=(l+r)>>1;
if(ql<=mid)modify_ban(k<<1,l,mid,ql,qr);
if(mid<qr)modify_ban(k<<1|1,mid+1,r,ql,qr);
pushup(k);
}
inline void recover(int k,int l,int r){
if(!need[k])return ;
if(ban[k])ban[k]=need[k]=false;
if(l==r){mx[k]=used[pos[l]]?mp(0,l):mp(val[pos[l]],l);return ;}
int mid=(l+r)>>1;
recover(k<<1,l,mid);
recover(k<<1|1,mid+1,r);
pushup(k);
}
inline void modify(int k,int l,int r,cs int &pos,cs int &val){
if(l==r){mx[k].fi=0;return ;}
int mid=(l+r)>>1;
if(pos<=mid)modify(k<<1,l,mid,pos,val);
else modify(k<<1|1,mid+1,r,pos,val);
pushup(k);
}
inline void find_conquer(int u){
used[u]=true;
modify_ban(1,1,n,in[u],out[u]);
u=fa[u];
while(u){
modify_ban(1,1,n,in[top[u]],in[u]);
u=fa[top[u]];
}
}
std::vector<int> vec;
signed main(){
n=getint();
for(int re i=1;i<=n;++i)val[i]=getint();
for(int re i=2;i<=n;++i)addedge(fa[i]=getint(),i);
dfs1(1),top[1]=1,dfs2(1);
build(1,1,n);
while(true){
if(mx[1].fi==0)break;
ans+=mx[1].fi;
vec.push_back(pos[mx[1].se]);
find_conquer(vec.back());
while(true){
if(mx[1].fi==0)break;
vec.push_back(pos[mx[1].se]);
find_conquer(vec.back());
}
recover(1,1,n);
for(int re i=0;i<vec.size();++i)modify(1,1,n,in[vec[i]],0);
vec.clear();
}
cout<<ans;
return 0;
}