蔬菜(vegetable)
题目描述
题目背景:您使用脚本刷出了上题游戏 998244353 关的最高分 (最优解),心满意足的准备点继续学习,忽然一条弹窗弹了出来:你想明白活着的意义吗?你想真正的...... 活着吗?YES or NO 作为一名新时代新青年,您当然不信这种扯淡的东西,毫不犹豫点击了 YES,于是当您醒来的时候,您已经在一片未知森林里了...
您正站在森林中最显眼的一棵树前,一条叫 Skqliao 的人正在树上打盹,他告诉您这棵树是一棵无根树,在第 i 个点上有 x 颗蔬菜,如果您想要回去的话就需要收集尽量多的蔬菜。当然乐于助人的 Skqliao 也会帮助您。具体来讲,首先你和 Skqliao 各选择一个不同的起点,接着轮流选定一个与自己相邻的且两人都未经过的点并到达该点。当某人无法移动时,另一人可以继续移动,直到两人都无法移动为止。当你或 Skqliao 经过某点时就可以收集该点所有蔬菜,请你制定合理策略 (包括 Skqliao 选择的初始位置和操作方式) 尝试获得最多的蔬菜。
输入
第一行一个整数nn,表示树的点数。
第二行有nn个整数,表示每个点上的蔬菜颗数xixi。
接下来n−1n−1行,每行两个整数u,vu,v,表示uu和vv之间有一条边。
输出
能获得的最多的蔬菜数量。
样例输入
<span style="color:#333333"><span style="color:#333333">6
10 8 6 4 2 1
1 2
1 3
2 4
2 5
2 6</span></span>
样例输出
<span style="color:#333333"><span style="color:#333333">30</span></span>
提示
对于30% 的数据,n≤15n≤15
对于50% 的数据,n≤100n≤100
对于70% 的数据,n≤5000n≤5000
另有10% 的数据树的形态为一条链
对于100% 的数据,n≤200000,0≤xi≤998244353n≤200000,0≤xi≤998244353
来源
solution
暴力卡过。
寻找正解请移步神犇博客(?)
可以先树形dp出每一个子树内的最长链
我们暴力枚举一个点,强制令一个点就在这棵树内
那么要修改的dp值为它到根
暴力改 效率O(n*平均深度)
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 200005
#define ll long long
using namespace std;
int n,head[maxn],tot,t1,t2,ft[maxn],flag[maxn],ban,pd;
ll s[maxn],f[maxn],l[maxn],F[maxn],L[maxn],ans;
struct node{
int v,nex;
}e[maxn*2];
void lj(int t1,int t2){
e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k,int fa){
ll m1=0,m2=0,ma=0;ft[k]=fa;
for(int i=head[k];i;i=e[i].nex){
if(e[i].v==fa)continue;
dfs(e[i].v,k);
if(l[e[i].v]>m1)m2=m1,m1=l[e[i].v];
else if(l[e[i].v]>m2)m2=l[e[i].v];
ma=max(ma,f[e[i].v]);
}
l[k]=m1+s[k];f[k]=max(ma,m1+m2+s[k]);
}
void dp(int k){
ll m1=0,m2=0,ma=0;
for(int i=head[k];i;i=e[i].nex){
if(e[i].v==ft[k])continue;
if(flag[e[i].v])dp(e[i].v);
if(e[i].v==ban)continue;
if(!flag[e[i].v]){
if(l[e[i].v]>m1)m2=m1,m1=l[e[i].v];
else if(l[e[i].v]>m2)m2=l[e[i].v];
ma=max(ma,f[e[i].v]);
}
else {
if(L[e[i].v]>m1)m2=m1,m1=L[e[i].v];
else if(L[e[i].v]>m2)m2=L[e[i].v];
ma=max(ma,F[e[i].v]);
}
}
L[k]=m1+s[k],F[k]=max(ma,m1+m2+s[k]);
}
int main()
{
freopen("vegetable.in","r",stdin);
freopen("vegetable.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)scanf("%lld",&s[i]);
for(int i=1;i<n;i++){
scanf("%d%d",&t1,&t2);
lj(t1,t2);lj(t2,t1);
if(t1!=t2+1&&t2!=t1+1)pd=1;
}
if(!pd){
for(int i=1;i<=n;i++)ans+=s[i];
cout<<ans<<endl;return 0;
}
dfs(1,0);
for(int b=2;b<=n;b++){
for(int i=ft[b];i;i=ft[i])flag[i]=1;
ban=b;dp(1);
ans=max(ans,f[b]+F[1]);
for(int i=ft[b];i;i=ft[i])flag[i]=F[i]=L[i]=0;
}
cout<<ans<<endl;
return 0;
}