【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); }
相关文章推荐
- 求hack or 证明(【JZOJ 4923】 【NOIP2017提高组模拟12.17】巧克力狂欢)
- 【JZOJ4923】【NOIP2017提高组模拟12.17】巧克力狂欢
- JZOJ4923. 【NOIP2017提高组模拟12.17】巧克力狂欢
- 【JZOJ 4922】【NOIP2017提高组模拟12.17】环
- {题解}[jzoj4924]【NOIP2017提高组模拟12.17】向再见说再见
- 【JZOJ 4924】 【NOIP2017提高组模拟12.17】向再见说再见
- 【JZOJ4922】【NOIP2017提高组模拟12.17】环
- 【JZOJ4924】【NOIP2017提高组模拟12.17】向再见说再见
- JZOJ 5371. 【NOIP2017提高A组模拟9.17】组合数问题
- JZOJ5377. 【NOIP2017提高A组模拟9.19】开拓 DP
- jzoj5290 【NOIP2017提高组A组模拟8.17】行程的交集 (树上路径交,dfs序+树状数组维护姿势)
- JZOJ 5398. 【NOIP2017提高A组模拟10.7】Adore
- JZOJ 5404. 【NOIP2017提高A组模拟10.10】Graph
- JZOJ 5197. 【NOIP2017提高组模拟7.3】C
- JZOJ 5389. 【NOIP2017提高A组模拟9.26】解梦
- jzoj5394 【NOIP2017提高A组模拟10.5】Ping
- JZOJ5394. 【NOIP2017提高A组模拟10.5】Ping 树上差分 树状数组
- JZOJ 5405. 【NOIP2017提高A组模拟10.10】Permutation
- 【JZOJ 5248】【NOIP2017提高A组模拟8.10】花花的聚会
- JZOJ 5195. 【NOIP2017提高组模拟7.3】A