2021 南京 H
H. Crystalfly
我们观察发现只有时间1和3才是有效的情况
我们首先来考虑只有1的情况
那我们设f[u]表示u点蝴蝶已经被驱散的子树的max
g[u]来表示u点蝴蝶没有被驱散的子树的max实际上g[u]只比f[u]多一个a[u]
我们只有1的情况就是选一个点g[v]其他都是f[v]我们维护一个s=/sigma f[v]
第一个转移就出来了:f[u]=max{s+mx} mx就是最大的a[v]
然后我们考虑要是有3这种节点存在
就表明我们可以先去一个节点之后再马上返回过来这个3的节点 但是先去的那个节点的子节点的蝴蝶显然已经消失了
所以这里我们维护一个h[u]表示u节点我们吃到了 但是u节点的子节点都消失了的值
第二个转移就是:f[u]=max{h[i]+g[j]+其他点的f[v]} [t[j]==3]
但是我们可以通过一些变形->f[u]=max{h[i]-f[i]+a[j]+s}
我们只需要维护a[j]的最大和次大就可以了 因为有可能这个h[i]的a[i]就是最大值 那时候我们就只能用次大
vector<int>g[N];
int f[N],h[N],n,a[N],t[N];
void dfs(int u,int fa){
int s=0,mx=0;
for(auto v:g[u]){
if(v==fa)continue;
dfs(v,u);
mx=max(mx,a[v]);
s+=f[v];
}
f[u]=mx+s;
pair<int,int> mx1={-INF,0},mx2={-INF,0};
for(auto v:g[u]){
if(v==fa||t[v]!=3)continue;
pair<int,int> mx3={a[v],v};
if(mx3>mx2)mx2=mx3;
if(mx2>mx1)swap(mx1,mx2);
}
for(auto v:g[u]){
if(v==fa)continue;
if(mx1.second!=v)f[u]=max(f[u],h[v]-f[v]+s+mx1.first);
else f[u]=max(f[u],h[v]-f[v]+s+mx2.first);
}
h[u]=s+a[u];
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++)f[i]=h[i]=0,g[i].clear();
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>t[i];
for(int i=1;i<n;i++){
int u,v;cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
cout<<f[1]+a[1]<<endl;
}