【NOIP2017提高組模擬12.17】巧克力狂歡
阿新 • • 發佈:2019-01-28
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);
}