您的位置:首页 > 其它

JZOJ 4923. 巧克力狂欢

2016-12-19 20:13 211 查看

题目

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

题解

(这种方法的题解很难写啊)

果断树形DP。
设F[x]表示一定不能再往上继续扩展(由于这是树形DP,先DP儿子的值,然后再将儿子的DP值返回给父亲,所以父亲加上儿子的DP值就叫向上扩展)的最大权值,ans[x]表示最大的权值(显然ans[x]包括f[x]),那么f[x]有几种转移:
1、f[x]=max(f[son x],ans[x])。//f[son x]表示不选择x这个点。
2、f[x]=max(f[x],最长链+次长链+当前子树中的最长"^"形链)。
3、f[x]=max(f[x],当前子树中的最长"^"形链+当前子树中的次长"^"形链)//这种情况显然。
4、f[x]=max(f[x],当前子树中最大的ans值+最长链)
ans[x]的转移如下:
ans[x]=max(ans[x],最长链+当前子树中的最长"^"形链)。//这种情况显然。
另外,如果这些值在同一个子树中,那么就换次大的值,如果还不行,就换第3大的值。
比如说,对于方程式2,如果当前子树中的最长"^"形链在最长链或次长链的子树中,就选当前子树 中的次长"^"形链,如果还是在,就选当前子树中的第3长"^"形链。


代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define N 200010
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL x,y,i,j,n,tot,ANS;
LL a
,ls
,g
,f
,ans
;
LL head
,go[N*2],next[N*2];
void lb(LL x,LL y)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
void dg(LL x,LL fa)
{
LL i,c1,c2,c3,g1,g2,g3,p1,p2;
c1=c2=c3=g1=g2=g3=p1=p2=0;
for(i=head[x];i;i=next[i])
{
LL now=go[i];
if (now==fa) continue;
dg(now,x);
if (ls[now]>ls[c1]) c3=c2,c2=c1,c1=now;else
if (ls[now]>ls[c2]) c3=c2,c2=now;else
if (ls[now]>ls[c3]) c3=now;
if (g[now]>g[g1]) g3=g2,g2=g1,g1=now;else
if (g[now]>g[g2]) g3=g2,g2=now;else
if (g[now]>g[g3]) g3=now;
if (f[now]>ans[p1]) p2=p1,p1=now;else
if (f[now]>ans[p2]) p2=now;
f[x]=max(f[now],ans[x]);
}
g[x]=max(g[g1],a[x]+ls[c1]+ls[c2]);
ls[x]=ls[c1]+a[x];
f[x]=max(f[x],g[g1]+g[g2]);
ans[x]=ans[p1]+a[x];
{
if (c1!=g1 && c2!=g1) f[x]=max(f[x],a[x]+ls[c1]+ls[c2]+g[g1]);
if (c1!=g1 && c3!=g1) f[x]=max(f[x],a[x]+ls[c1]+ls[c3]+g[g1]);
if (c2!=g1 && c3!=g1) f[x]=max(f[x],a[x]+ls[c2]+ls[c3]+g[g1]);
if (c1!=g2 && c2!=g2) f[x]=max(f[x],a[x]+ls[c1]+ls[c2]+g[g2]);
if (c1!=g2 && c3!=g2) f[x]=max(f[x],a[x]+ls[c1]+ls[c3]+g[g2]);
if (c2!=g2 && c3!=g2) f[x]=max(f[x],a[x]+ls[c2]+ls[c3]+g[g2]);
if (c1!=g3 && c2!=g3) f[x]=max(f[x],a[x]+ls[c1]+ls[c2]+g[g3]);
if (c1!=g3 && c3!=g3) f[x]=max(f[x],a[x]+ls[c1]+ls[c3]+g[g3]);
if (c2!=g3 && c3!=g3) f[x]=max(f[x],a[x]+ls[c2]+ls[c3]+g[g3]);
}
{
if (c1!=p1) f[x]=max(f[x],a[x]+ls[c1]+ans[p1]);
if (c1!=p2) f[x]=max(f[x],a[x]+ls[c1]+ans[p2]);
if (c2!=p1) f[x]=max(f[x],a[x]+ls[c2]+ans[p1]);
if (c2!=p2) f[x]=max(f[x],a[x]+ls[c2]+ans[p2]);
if (c3!=p1) f[x]=max(f[x],a[x]+ls[c3]+ans[p1]);
if (c3!=p2) f[x]=max(f[x],a[x]+ls[c3]+ans[p2]);
}
{
if (c1!=g1) ans[x]=max(ans[x],a[x]+ls[c1]+g[g1]);
if (c2!=g1) ans[x]=max(ans[x],a[x]+ls[c2]+g[g1]);
if (c3!=g1) ans[x]=max(ans[x],a[x]+ls[c3]+g[g1]);
if (c1!=g2) ans[x]=max(ans[x],a[x]+ls[c1]+g[g2]);
if (c2!=g2) ans[x]=max(ans[x],a[x]+ls[c2]+g[g2]);
if (c3!=g2) ans[x]=max(ans[x],a[x]+ls[c3]+g[g2]);
if (c1!=g3) ans[x]=max(ans[x],a[x]+ls[c1]+g[g3]);
if (c2!=g3) ans[x]=max(ans[x],a[x]+ls[c2]+g[g3]);
if (c3!=g3) ans[x]=max(ans[x],a[x]+ls[c3]+g[g3]);
}
}
int main()
{
scanf("%lld",&n);
fo(i,1,n) scanf("%lld",&a[i]);
fo(i,1,n-1)
{
scanf("%lld %lld",&x,&y);
lb(x,y);lb(y,x);
}
dg(1,-1);
ANS=max(f[1],ans[1]);
printf("%lld",ANS);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: