您的位置:首页 > 其它

【JZOJ 4923】【NOIP2017提高组模拟12.17】巧克力狂欢

2016-12-17 20:47 609 查看

Description

Alice和Bob有一棵树(无根、无向),在第i个点上有ai个巧克力。首先,两人个选择一个起点(不同的),获得点上的巧克力;接着两人轮流操作(Alice先),操作的定义是:在树上找一个两人都没选过的点并获得点上的巧克力,并且这个点要与自己上一次选的点相邻。当有一人无法操作 时,另一个人可以继续操作,直到不能操作为止。因为Alice和Bob是好朋友,所以他们希望两人得到的巧克力总和尽量大,请输出最大总和。

Data Constraint

对于20%的数据,n<=15

对于40%的数据,n<=100

对于60%的数据,n<=5000

对于100%的数据,n<=200000,0<=ai<=1000000000(1e9)

Solution

这道题显然一眼就知道是树形dp。我们要处理的是在树上找两条不相交的最长链。现在这两条链有两种关系:

1、这两条链的最高点不存在祖先或儿子的关系。这种情况很好处理。我们对于每个点处理一个d[i]和g[i],d[i]表示以i为根的子树中一个端点为i的最长链。g[i]表示以i为根的子树中的最长链。转移显然。统计一下一个父亲的儿子中最大的g和次大的g,相加更新一下答案即可。

2、这两条链的最高点存在祖先或儿子的关系。我们在做完情况一之后再做一遍dfs。对于每个点i,假如他要走到儿子x,我们是可以计算出整棵树中不经过以x为根的子树的最长链的,然后整棵树中不经过以x为根的子树的最长链的长度加上以x为根的子树中一个端点为i的最长链的长度即可拿来更新答案。计算出整棵树中不经过以x为根的子树的最长链可以维护一个从i父亲传来的最长链,并与i的除x以外的到i的最长链相比较(可以通过计算最长链与次大链O(1)得到),取一个最长的与次大的相加即可。同时将所得传向x,继续上述操作。

Code

#include<iostream>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=4*1e5+5;
ll first[maxn],last[maxn],next[maxn],a[maxn],d[maxn],g[maxn];
ll n,i,t,j,k,l,x,y,num,ans,mx,p;
bool bz[maxn];
void lian(int x,int y){
last[++num]=y;next[num]=first[x];first[x]=num;
}
void dg(int x,int y){
ll t,k=0,k1=0,p=0,p1=0;
for (t=first[x];t;t=next[t]){
if (last[t]==y) continue;
dg(last[t],x);
d[x]=max(d[x],d[last[t]]);
if (d[last[t]]>k) k1=k,k=d[last[t]];
else if (d[last[t]]>k1) k1=d[last[t]];
if (g[last[t]]>p) p1=p,p=g[last[t]];
else if (g[last[t]]>p1) p1=g[last[t]];
}
d[x]+=a[x];
g[x]=max(k+k1+a[x],p);
g[x]=max(g[x],p1);
ans=max(p+p1,ans);
}
void dfs(int x,int y,ll sum){
ll t,k=0,k1=0,k2=0,k3=0;
if (x==4){
t=1;
}
if (sum+a[x]>d[x]) d[x]=sum+a[x],k++;
else k1=sum,k3=1;
for (t=first[x];t;t=next[t]){
if (last[t]==y) continue;
if (d[last[t]]+a[x]==d[x]) k++;
else if (k1==d[last[t]]) k3++;
else if (k1<d[last[t]]) k2=k1,k1=d[last[t]],k3=1;
else k2=max(k2,d[last[t]]);
}
for (t=first[x];t;t=next[t]){
if (last[t]==y) continue;
if (d[last[t]]+a[x]==d[x]){
if (k>1){
if (k>2) ans=max(ans,2*d[x]-a[x]+g[last[t]]);
else ans=max(ans,d[x]+k1+g[last[t]]);
dfs(last[t],x,d[x]);
}else{
if (k3>1) ans=max(ans,k1*2+a[x]+g[last[t]]);
else ans=max(ans,k1+k2+a[x]+g[last[t]]);
dfs(last[t],x,k1+a[x]);
}
}else{
if (k>1) ans=max(ans,2*d[x]-a[x]+g[last[t]]);
else if (d[last[t]]==k1) ans=max(ans,d[x]+k2+g[last[t]]);
else ans=max(ans,d[x]+k1+g[last[t]]);
dfs(last[t],x,d[x]);
}
}
}
int main(){
freopen("data.in","r",stdin);
scanf("%lld",&n);
for (i=1;i<=n;i++)
scanf("%lld",&a[i]);
for (i=1;i<n;i++)
scanf("%lld%lld",&x,&y),lian(x,y),lian(y,x);
dg(1,0);
dfs(1,0,0);
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: