1. 程式人生 > >【NOIP2017提高組模擬12.17】巧克力狂歡

【NOIP2017提高組模擬12.17】巧克力狂歡

Description

Alice和Bob有一棵樹(無根、無向),在第i個點上有ai個巧克力。首先,兩人個選擇一個起點(不同的),獲得點上的巧克力;接著兩人輪流操作(Alice先),操作的定義是:在樹上找一個兩人都沒選過的點並獲得點上的巧克力,並且這個點要與自己上一次選的點相鄰。當有一人無法操作 時,另一個人可以繼續操作,直到不能操作為止。因為Alice和Bob是好朋友,所以他們希望兩人得到的巧克力總和儘量大,請輸出最大總和。

Solution

我們可以發現,答案一定是由兩條不想交的鏈組成的。
那麼問題就是怎麼處理,發現打的時候,如果兩段鏈最近的距離只差1的話會很難搞。
我們分類討論一下:
1、兩段鏈的最高點,互不為祖輩關係,那麼這個很好處理,最大值+次大值就好了。
2、當兩段鏈的最高點有一個是另一個的祖先的話,那麼我們列舉一個x,那麼x的一個節點y中選取y的子樹內的最大鏈,然後x有兩種情況,一個是除了y的其他兒子的最大值和次大值組合起來,或者是x向下延伸,然後在向上延伸再從一個z點折下來。
用DP處理一下就可以了。

Code

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int
maxn=2e5+7; int i,j,k,l,t,n,m; int first[maxn*2],last[maxn*2],next[maxn*2],num; ll a[maxn],f[maxn],g[maxn],b,c,ans; ll d[maxn],qian[maxn],hou[maxn]; ll qc[maxn],hc[maxn],p[maxn]; ll da1,cda1; void add(int x,int y){ last[++num]=y,next[num]=first[x],first[x]=num; } void dfs(int x,int y){ int i; ll da=0
,cda=0,yi=0,er=0; rep(i,x){ if(last[i]!=y){ dfs(last[i],x); g[x]=max(g[x],g[last[i]]); f[x]=max(f[x],f[last[i]]); if(da<g[last[i]])cda=da,da=g[last[i]]; else if(g[last[i]]>cda)cda=g[last[i]]; if(yi<f[last[i]])er=yi,yi=f[last[i]]; else if(f[last[i]]>er)er=f[last[i]]; } } g[x]+=a[x]; f[x]=max(f[x],a[x]+da+cda); ans=max(ans,yi+er); } void dfs1(int x,int y,ll z){ int i,j; ll da=0,cda=0; rep(i,x){ if(last[i]!=y){ if(da<g[last[i]])cda=da,da=g[last[i]]; else if(g[last[i]]>cda)cda=g[last[i]]; } } rep(i,x){ if(last[i]!=y){ if(g[last[i]]==da){ if(z<cda)dfs1(last[i],x,cda+a[x]); else dfs1(last[i],x,z+a[x]); } else{ if(z<da)dfs1(last[i],x,da+a[x]); else dfs1(last[i],x,z+a[x]); } } } d[0]=0; rep(i,x)if(last[i]!=y)d[++d[0]]=last[i]; qian[0]=qc[0]=0; hou[d[0]+1]=hc[d[0]+1]=0; if(x==4){ ans=ans; } fo(i,1,d[0]){ if(g[d[i]]>qian[i-1])qc[i]=qian[i-1],qian[i]=g[d[i]]; else if(g[d[i]]>qc[i-1])qian[i]=qian[i-1],qc[i]=g[d[i]]; else qian[i]=qian[i-1],qc[i]=qc[i-1]; } fod(i,d[0],1){ if(g[d[i]]>hou[i+1])hc[i]=hou[i+1],hou[i]=g[d[i]]; else if(g[d[i]]>hc[i+1])hou[i]=hou[i+1],hc[i]=g[d[i]]; else hou[i]=hou[i+1],hc[i]=hc[i+1]; } fo(i,1,d[0]){ da=cda=0; if(qian[i-1]>da)cda=da,da=qian[i-1]; else if(qian[i-1]>cda)cda=qian[i-1]; if(qc[i-1]>da)cda=da,da=qc[i-1]; else if(qc[i-1]>cda)cda=qc[i-1]; if(hou[i+1]>da)cda=da,da=hou[i+1]; else if(hou[i+1]>cda)cda=hou[i+1]; if(hc[i+1]>da)cda=da,da=hc[i+1]; else if(hc[i+1]>cda)cda=hc[i+1]; ans=max(ans,da+cda+a[x]+f[d[i]]); ans=max(ans,z+a[x]+da+f[d[i]]); } } int main(){ // freopen("fan.in","r",stdin); scanf("%d",&n); fo(i,1,n)scanf("%d",&a[i]); fo(i,1,n-1){ scanf("%d%d",&k,&l); add(k,l),add(l,k); } dfs(1,0); dfs1(1,0,0); printf("%lld\n",ans); }