Description
Alice和Bob有一棵树(无根、无向),在第i个点上有ai个巧克力。首先,两人个选择一个起点(不同的),获得点上的巧克力;接着两人轮流操作(Alice先),操作的定义是:在树上找一个两人都没选过的点并获得点上的巧克力,并且这个点要与自己上一次选的点相邻。当有一人无法操作 时,另一个人可以继续操作,直到不能操作为止。因为Alice和Bob是好朋友,所以他们希望两人得到的巧克力总和尽量大,请输出最大总和。
Input
第一行一个整数n,表示树的点数
第二行有n个整数,表示每个点上的巧克力数量ai
接下来n-1行,每行两个整数u、v,表示u和v之间有一条边。
Output
输出一个整数,表示两人能获得得巧克力的最大总和。
Sample Input
9
1 2 3 4 5 6 7 8 9
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
Sample Output
25
Data Constraint
对于20%的数据,n<=15
对于40%的数据,n<=100
对于60%的数据,n<=5000
对于100%的数据,n<=200000,0<=ai<=1000000000(1e9)
分析
题目的意思就是要找两条不相交的链,使它们的和最大。
就分两种情况进行讨论。
第一种情况,其中一条链与树的直径不相交,那么也就是说,
两条链分别就是一条直径,和一条与直径不相交的最长链。
处理起来也比较简单,
先找一条直径,这条直径会将这棵树分成很多部分,只要在每一部分找一下最长链就可以了。
第二种情况,就麻烦一点,两条链都与直径有公共部分。
已知中间那条链是直径(点权省略),直径的右端部分与其中一条链(红色部分)相交,
现在我们对另一条链进行选择,
一种方案是选择绿色加上蓝色,另一种方案是选择绿色和黄色。根据直径的性质可以知道黄色的部分一定大于或者等于蓝色的部分,否则黄色的部分就不应该是直径。
从中我们可以得出一个结论,如果某一条链与直径相交,那么这条链最长的情况就应该是链的一个端点在直径的端点上面。
也就是说,这两条链的组成就是从直径的左端点开始,到直径上的某个点,然后就这条链离开直径,另外一条链的组成也大致相同,只要保证它们在直径上面不相交就可以了。
处理起来也比较简单,
首先先找到一条直径,然后以直径上的每一个点开始,找一条不与直径相交的最长链,然后对这些链之间进行两两匹配。
而在两两匹配的时候,从直径的左端向右端枚举,记录左端的最大值,用这个最大值和当前这个点匹配,然后用当前这个点去更新这个最大值。
最后就将两种情况合并一下就可以了。
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define N 200003
#define ll long long
using namespace std;
int a[2*N],next[2*N],b[N],m,w[N],t[N];
ll f[N],ans,v[N],tt,g,mx,ans1,sum;
bool bz[N];
int n,x,y;
void ins(int x,int y)
{
next[++m]=b[x];
a[m]=y;
b[x]=m;
}
void dg(int x,int fa,ll s)
{
for(int i=b[x];i;i=next[i])
if((a[i]!=fa)&&(bz[a[i]]))dg(a[i],x,s+v[a[i]]);
if(s>tt)tt=s,g=x;
}
void dg4(int x,int fa,ll s)
{
bz[x]=0;
for(int i=b[x];i;i=next[i])
if((a[i]!=fa)&&(bz[a[i]]))dg4(a[i],x,s+v[a[i]]);
if(s>tt)tt=s,g=x;
}
void dg1(int y,int x,int fa,ll s)
{
for(int i=b[x];i;i=next[i])
if(a[i]!=fa)
{
w[y]=a[i];
dg1(y+1,a[i],x,s+v[a[i]]);
}
if(s>=tt)
{
tt=s;
g=y-1;
memcpy(t,w,sizeof(t));
}
}
void dg3(int y,int x,int fa,ll s)
{
for(int i=b[x];i;i=next[i])
if(a[i]!=fa)dg3(y,a[i],x,s+v[a[i]]);
if(s>f[y])f[y]=s;
}
int main()
{
memset(bz,1,sizeof(bz));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&v[i]);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
ins(x,y);
ins(y,x);
}
dg(1,0,v[1]);
w[1]=g;
dg1(2,g,0,v[g]);
for(int i=1;i<=g;i++)
{
bz[t[i]]=0;
for(int j=b[t[i]];j;j=next[j])
if((a[j]!=t[i-1])&&(a[j]!=t[i+1]))dg3(i,a[j],t[i],v[a[j]]);
if(f[i]+tt-sum+mx>ans)ans=f[i]+tt-sum+mx;
sum=sum+v[t[i]];
if(f[i]+sum>mx)mx=f[i]+sum;
}
mx=0;
for(int i=1;i<=n;i++)
{
if(bz[i])
{
tt=g=0;
dg(i,0,v[i]);
dg4(g,0,v[g]);
mx=max(mx,tt);
}
}
ans=max(ans,sum+mx);
printf("%lld",ans);
}