1. 程式人生 > >求hack or 證明(【JZOJ 4923】 【NOIP2017提高組模擬12.17】巧克力狂歡)

求hack or 證明(【JZOJ 4923】 【NOIP2017提高組模擬12.17】巧克力狂歡)

() LG 接下來 clu mailto 得到 方法 出發 printf

前言

本人在此題有一種不是題解的方法,但無法證明也找不到反例。
如果各位大神有反例或證明請發至
郵箱:[email protected]

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)

我的方法

首先隨便找一條直徑,然後刪掉這些的,在剩下的森林中再找一條最長的鏈,輸出總和。

或者,
首先隨便找一條直徑,枚舉這條直徑上的兩個點,從這兩個點出發分別找到最長鏈,答案就是這條直徑加上從枚舉的兩個點找到的最長鏈再減去枚舉的兩個點在直徑之間的路徑。

將兩者去最大值輸出。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const long long maxlongint=2147483647;
const long long mo=1000000007;
const long long N=200005;
using namespace std;
long long n,v[N],next[N*2],last[N*2],to[N*2],tot,ans,mxp,pos,bz[N],s,t,st[N],ts[N],num,ans1,ans2,ans3,ans4,ans5,vv;
long long bj(long long x,long long y)
{
    next[++tot]=last[x];
    last[x]=tot;
    to[tot]=y;
}
long long dg(long long x,long long fa,long long sum)
{
    if(sum>ans) ans=sum,mxp=x;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa && bz[j]==0) dg(j,x,sum+v[j]);
    }
}
long long dg1(long long x,long long fa)
{
    if(mxp==x && !bz[x]) bz[x]=vv;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa && bz[j]==0) 
        {
            dg1(j,x);
            if(bz[j]) 
            {
                bz[x]=vv;
                break;
            }
        }
    }
}
long long dg2(long long x,long long fa,long long sum)
{
    ans=0;
    dg(x,fa,0);
    st[++tot]=ans+sum;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa && bz[j]==vv) 
        {
            dg2(j,x,sum+v[j]);
        }
    }
}
long long dg3(long long x,long long fa,long long sum)
{
    ans=0;
    dg(x,fa,0);
    ts[tot--]=ans+sum;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa && bz[j]==vv) 
        {
            dg3(j,x,sum+v[j]);
        }
    }
}
int main()
{
    scanf("%lld",&n);
    for(long long i=1;i<=n;i++) scanf("%lld",&v[i]);
    for(long long i=1;i<=n-1;i++)
    {
        long long x,y;
        scanf("%lld%lld",&x,&y);
        bj(x,y);
        bj(y,x);
    }
    vv++;
    dg(1,0,v[1]);
    pos=mxp;
    ans=0;
    dg(pos,0,v[pos]);
    dg1(pos,0);
    s=mxp;
    ans=0;
    dg(pos,0,v[pos]);
    dg1(pos,0);
    t=mxp;
    tot=0;
    dg2(s,0,v[s]);
    num=tot;
    dg3(t,0,v[t]);
    ans1=st[num];
    for(int i=1;i<=num;i++) st[i]=max(st[i],st[i-1]);
    for(int i=num;i>=1;i--) ts[i]=max(ts[i],ts[i+1]);
    ans=0;
    for(int i=1;i<=num-1;i++) ans=max(ans,st[i]+ts[i+1]);
    ans5=ans;
    for(int k=1;k<=n;k++)
    if(!bz[k])
    {
        vv++;
        tot=0;
        num=0;
        ans=0;
        dg(k,0,v[k]);
        pos=mxp;
        ans=0;
        dg(pos,0,v[pos]);
        dg1(pos,0);
        s=mxp;
        ans=0;
        dg(pos,0,v[pos]);
        dg1(pos,0);
        t=mxp;
        tot=0;
        dg2(s,0,v[s]);
        num=tot;
        ans3=max(ans3,st[num]);
    }
    printf("%lld",max(ans5,ans1+ans3));
}

求hack or 證明(【JZOJ 4923】 【NOIP2017提高組模擬12.17】巧克力狂歡)