题意
一颗树,在边上移动的时间花费为1。每个点有两个权 a a a和 t t t, a a a是一个只能被获取一次的点权, t t t代表当第一次进入这个点的相邻点后多久,这个点的第一个权 a a a会消失。 t t t的取值范围为 1 1 1到 3 3 3.现在你从 1 1 1号点开始,任意游走,请问最大能获得的 a a a是多少。
思路
需要特殊关注的是 t t t的范围,一到三。假如我们任意跑到了一个点,那么他的子节点会立即开始计时。假如有若干个子树。我有如下两种抉择:走到其中一棵子树 v v v,之后一路获取 v v v子树的权,最后再去别的子树。第二种是我先前往 v v v,之后不去管 v v v的子节点,返回根,再去另一个子树 w w w。这样操作的话, w w w的 t t t只能为 3 3 3才能有收益, 1 1 1或者 2 2 2都会导致 w w w的权在触及时已经消失了。是不是还有别的反复横跳的操作呢?不会的,因为最多只能获得两个子节点的 a a a,多次操作反而会使得子树中更多点消失。
我们分别考虑这两种操作。为方便描述,设置如下记号:设 a x a_x ax为上文 x x x的第一个权, t x t_x tx为第二个权。 f x f_x fx为 x x x的第一权为 0 0 0后,初次到达 x x x后能其子树能获得的最大收益。 g x g_x gx设为x所有子节点 y i y_i yi的 f y i f_{y_i} fyi之和。 h x h_x hx为 a x − f x + g x a_x - f_x + g_x ax−fx+gx。显然最终输出的答案应为 a 1 + f 1 a_1+f_1 a1+f1。
对于第一种操作,我们走到了
x
x
x的
v
v
v子树,并一路处理下去,那么我们相当于在
x
x
x的子节点中,只有
v
v
v子树能获得完整的收益
a
v
+
f
v
a_v+f_v
av+fv,别的子节点
w
i
w_i
wi都只能获得
f
w
i
f_{w_i}
fwi的收益。那么第一种操作的转移就是
f
x
=
max
y
{
a
y
}
+
g
x
f_x=\max_{y}\{a_y\}+g_x
fx=ymax{ay}+gx
对于第二种操作,我们先进入
v
v
v子树,再回到
w
w
w子树并操作,那么对于
w
w
w子树,可以获得完满的收益
a
w
+
f
w
a_ w+f_w
aw+fw,那对于
v
v
v子树,首先肯定可以获得一个
a
v
a_v
av,之后我们能获得
f
v
f_v
fv吗?不可以的,因为当到达
v
v
v时子节点就开始计时了,离开再返回它的子节点们的权值早已消散,那么其实他的收获应该是
g
v
g_v
gv。所以最终的转移也就是
f
x
=
max
u
,
v
u
!
=
v
a
n
d
t
v
=
3
{
g
u
+
f
v
+
a
u
+
a
v
+
∑
k
k
!
=
u
a
n
d
k
!
=
v
f
k
}
=
g
x
+
max
u
,
v
u
!
=
v
a
n
d
t
v
=
3
{
a
u
+
a
v
−
f
u
+
g
u
}
=
g
x
+
max
u
,
v
u
!
=
v
a
n
d
t
v
=
3
{
h
u
+
a
v
}
f_x=\max_{u,v\;u!=v\; and \; t_v=3}\{g_u+f_v+a_u+a_v+\sum_{k\;k!=u\;and\;k!=v}f_k\} \\=g_x+\max_{u,v\;u!=v\; and \; t_v=3}\{a_u+a_v-f_u+g_u\} \\=g_x+\max_{u,v\;u!=v\; and \; t_v=3}\{h_u+a_v\}
fx=u,vu!=vandtv=3max{gu+fv+au+av+kk!=uandk!=v∑fk}=gx+u,vu!=vandtv=3max{au+av−fu+gu}=gx+u,vu!=vandtv=3max{hu+av}
对于最后一个
max
\max
max的维护,维护子节点的
h
h
h最大值和次大值就好了,复杂度是同阶的,引入set等乱搞也是可以的,亲测没有慢多少
复杂度
O
(
n
+
m
)
O(n+m)
O(n+m)
教训/收获
代码
#include<cstdio>
#include<iostream>
#include<set>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#include<bitset>
#include<functional>
#include<complex>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define de(i) cout<<#i<<": "<<i<<endl;
#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=1000005;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,m,k;
int a[maxn],t[maxn];
int f[maxn],g[maxn],h[maxn];
vector<int>e[maxn];
void dp(int x,int fa){
int maxx=-inf;
pair<int,int>max1H={-inf,-inf},max2H={-inf,-inf};
int son=0;
for(auto y:e[x]){
if(y==fa)continue;
dp(y,x);
son++;
g[x]+=f[y];
maxx=max(maxx,a[y]);
if(h[y]>=max1H.first){
max2H=max1H;
max1H={h[y],y};
}
else if(h[y]>=max2H.first)
max2H={h[y],y};
}
if(son>1){
for(auto y:e[x]){
if(y==fa)continue;
if(t[y]==3){
if(max1H.second==y){
maxx=max(maxx,a[y]+max2H.first);
}
else{
maxx=max(maxx,a[y]+max1H.first);
}
}
}
}
f[x]=max(f[x],g[x]+maxx);
h[x]=a[x]-f[x]+g[x];
}
void init(){
for(int i=1;i<=n;i++){
f[i]=0;g[i]=0;h[i]=0;e[i].clear();
}
}
void solve(){
cin>>n;
init();
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;
e[u].push_back(v);
e[v].push_back(u);
}
dp(1,-1);
cout<<f[1]+a[1]<<endl;
}
signed main(){
IOS
#ifdef THESUNSPOT
auto st=clock();
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
solve();
}
#ifdef THESUNSPOT
auto ed=clock();
cout<<endl<<"time: "<<ed-st<<"ms."<<endl;
srand(time(0));
cout<<"version: "<<rand()%1000<<endl;
#endif
}