【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
#include
#include
#include
#include
#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(dalast[i]])cda=da,da=g[last[i]];
            else if(g[last[i]]>cda)cda=g[last[i]];
            if(yilast[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(dalast[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(zlast[i],x,cda+a[x]);
                else dfs1(last[i],x,z+a[x]);
            }
            else{
                if(zlast[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);
}

你可能感兴趣的:(noip,DP)