点亮
题意


题解
对于40%的数据,乱整
题目中多次强调:随机得到的树
来来来直接上性质众所周知?不存在的
综上,题解的意思是:随机一般是用来暴力骗分,但是这道题就是正解
下面是性质的证明
(突然发现自己在疯狂粘题解)
由于这个深度很小,所以我们可以状压
把所有的输入处理到LCA上
然后就可以dp了,d(i,j,k)表示i子树,状态为j,点亮k个
树上背包式的转移即可,注意分类讨论k与(sz+1)/2的关系
由于状态太多,所以干脆在每次操作中枚举状态
就酱吧
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1005;
const int L=13;
const int INF=1<<30;
int n,d[N][N],fa[N][L+2];
int l[N][N],deep[N];
int sz[N],ans,val[N][N][2],sta[N];
struct node{
int u,v,nxt;
}edge[N*2];
int head[N],mcnt;
void add_edge(int u,int v){
mcnt++;
edge[mcnt].u=u;
edge[mcnt].v=v;
edge[mcnt].nxt=head[u];
head[u]=mcnt;
}
void dfs1(int u,int d){
sz[u]=1,deep[u]=d;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
dfs1(v,d+1);
sz[u]+=sz[v];
}
}
int LCA(int u,int v){
if(deep[u]<deep[v])
swap(u,v);
for(int t=L;t>=0;t--)
if(deep[fa[u][t]]>=deep[v])
u=fa[u][t];
if(u==v)
return u;
for(int t=L;t>=0;t--)
if(fa[u][t]!=fa[v][t])
u=fa[u][t],v=fa[v][t];
return fa[u][0];
}
void dfs2(int u,int fa,int dep){
int tmp[N];
for(int i=0;i<=sz[u];i++)
d[u][i]=-INF;
sta[dep]=1,d[u][1]=0;
for(int i=1;i<=dep;i++)
if(sta[i])
d[u][1]+=val[u][i][1];
if(sz[u]>1){
d[u][0]=0;
for(int i=1;i<=dep;i++)
if(!sta[i])
d[u][0]+=val[u][i][0];
}
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
dfs2(v,u,dep+1);
for(int i=sz[u];i>=0;i--){
d[u][i]+=d[v][0];
for(int j=1;j<=sz[v]&&j<=i;j++)
d[u][i]=max(d[u][i],d[u][i-j]+d[v][j]);
}
}
memcpy(tmp,d[u],sizeof(d[u]));
for(int i=0;(i<<1)<sz[u];i++)
tmp[i]=-INF;
for(int i=0;i<=sz[u];i++)
d[u][i]=-INF;
sta[dep]=0;
if(sz[u]>1){
d[u][1]=0;
for(int i=1;i<=dep;i++)
if(sta[i])
d[u][1]+=val[u][i][1];
}
d[u][0]=0;
for(int i=1;i<=dep;i++)
if(!sta[i])
d[u][0]+=val[u][i][0];
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
dfs2(v,u,dep+1);
for(int i=sz[u];i>=0;i--){
d[u][i]+=d[v][0];
for(int j=1;j<=sz[v]&&j<=i;j++)
d[u][i]=max(d[u][i],d[u][i-j]+d[v][j]);
}
}
for(int i=(sz[u]+1)>>1;i<=sz[u];i++)
d[u][i]=-INF;
for(int i=0;i<=sz[u];i++)
d[u][i]=max(d[u][i],tmp[i]);
}
void Read(int &x){
char c=getchar();
int f=1; x=0;
while((c<'0'||c>'9')&&c!='-')
c=getchar();
if(c=='-')
f=-1,c=getchar();
while(c>='0'&&c<='9')
x=x*10+c-'0',c=getchar();
x*=f;
}
int main()
{
freopen("light.in","r",stdin);
freopen("light.out","w",stdout);
Read(n);
for(int i=2;i<=n;i++){
Read(fa[i][0]);
add_edge(fa[i][0],i);
}
dfs1(1,1);
for(int j=1;j<=L;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
l[i][j]=l[j][i]=LCA(i,j);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j){
int a,b;
Read(a);
Read(b);
val[i][deep[l[i][j]]][0]+=a;
val[i][deep[l[i][j]]][1]+=b;
}
dfs2(1,0,1);
for(int i=0;i<=n;i++)
ans=max(ans,d[1][i]);
printf("%d\n",ans);
}