• 蔬菜(vegetable)


    蔬菜(vegetable)

    题目描述

     

    题目背景:您使用脚本刷出了上题游戏 998244353 关的最高分 (最优解),心满意足的准备点继续学习,忽然一条弹窗弹了出来:你想明白活着的意义吗?你想真正的...... 活着吗?YES or NO 作为一名新时代新青年,您当然不信这种扯淡的东西,毫不犹豫点击了 YES,于是当您醒来的时候,您已经在一片未知森林里了...

     

    您正站在森林中最显眼的一棵树前,一条叫 Skqliao 的人正在树上打盹,他告诉您这棵树是一棵无根树,在第 i 个点上有 x 颗蔬菜,如果您想要回去的话就需要收集尽量多的蔬菜。当然乐于助人的 Skqliao 也会帮助您。具体来讲,首先你和 Skqliao 各选择一个不同的起点,接着轮流选定一个与自己相邻的且两人都未经过的点并到达该点。当某人无法移动时,另一人可以继续移动,直到两人都无法移动为止。当你或 Skqliao 经过某点时就可以收集该点所有蔬菜,请你制定合理策略 (包括 Skqliao 选择的初始位置和操作方式) 尝试获得最多的蔬菜。

     

    输入

     

    第一行一个整数nn,表示树的点数。

    第二行有nn个整数,表示每个点上的蔬菜颗数xixi。

    接下来n−1n−1行,每行两个整数u,vu,v,表示uu和vv之间有一条边。

     

    输出

     

    能获得的最多的蔬菜数量。

     

    样例输入

    <span style="color:#333333"><span style="color:#333333">6
    10 8 6 4 2 1
    1 2
    1 3
    2 4
    2 5
    2 6</span></span>

    样例输出

    <span style="color:#333333"><span style="color:#333333">30</span></span>

    提示

     

    对于30% 的数据,n≤15n≤15

    对于50% 的数据,n≤100n≤100

    对于70% 的数据,n≤5000n≤5000

    另有10% 的数据树的形态为一条链

    对于100% 的数据,n≤200000,0≤xi≤998244353n≤200000,0≤xi≤998244353

     

    来源

    noip2018模拟-北京十一


    solution

    暴力卡过。

    寻找正解请移步神犇博客(?)

    可以先树形dp出每一个子树内的最长链

    我们暴力枚举一个点,强制令一个点就在这棵树内

    那么要修改的dp值为它到根

    暴力改 效率O(n*平均深度)

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 200005
    #define ll long long
    using namespace std;
    int n,head[maxn],tot,t1,t2,ft[maxn],flag[maxn],ban,pd;
    ll s[maxn],f[maxn],l[maxn],F[maxn],L[maxn],ans;
    struct node{
        int v,nex;
    }e[maxn*2];
    void lj(int t1,int t2){
        e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
    }
    void dfs(int k,int fa){
        ll m1=0,m2=0,ma=0;ft[k]=fa;
        for(int i=head[k];i;i=e[i].nex){
            if(e[i].v==fa)continue;
            dfs(e[i].v,k);
            if(l[e[i].v]>m1)m2=m1,m1=l[e[i].v];
            else if(l[e[i].v]>m2)m2=l[e[i].v];
            ma=max(ma,f[e[i].v]);
        }
        l[k]=m1+s[k];f[k]=max(ma,m1+m2+s[k]);
    }
    void dp(int k){
        ll m1=0,m2=0,ma=0;
        for(int i=head[k];i;i=e[i].nex){
            if(e[i].v==ft[k])continue;
            if(flag[e[i].v])dp(e[i].v);
            if(e[i].v==ban)continue;
            if(!flag[e[i].v]){
                if(l[e[i].v]>m1)m2=m1,m1=l[e[i].v];
                else if(l[e[i].v]>m2)m2=l[e[i].v];
                ma=max(ma,f[e[i].v]);
            }
            else {
                if(L[e[i].v]>m1)m2=m1,m1=L[e[i].v];
                else if(L[e[i].v]>m2)m2=L[e[i].v];
                ma=max(ma,F[e[i].v]);
            }
        }
        L[k]=m1+s[k],F[k]=max(ma,m1+m2+s[k]);
    }
    int main()
    {
        freopen("vegetable.in","r",stdin);
        freopen("vegetable.out","w",stdout);
        cin>>n;
        for(int i=1;i<=n;i++)scanf("%lld",&s[i]);
        for(int i=1;i<n;i++){
            scanf("%d%d",&t1,&t2);
            lj(t1,t2);lj(t2,t1);
            if(t1!=t2+1&&t2!=t1+1)pd=1;
        }
        if(!pd){
            for(int i=1;i<=n;i++)ans+=s[i];
            cout<<ans<<endl;return 0;
        }
        dfs(1,0);
        for(int b=2;b<=n;b++){
            for(int i=ft[b];i;i=ft[i])flag[i]=1;
            ban=b;dp(1);
            ans=max(ans,f[b]+F[1]);
            for(int i=ft[b];i;i=ft[i])flag[i]=F[i]=L[i]=0;
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    7-9 红色警报 (25 分) 数据结构连通分量应用
    & | ^运算
    Codeblocks自动代码格式化快捷键(自带)
    网络攻击与防御实验四
    网络攻击与防御实验三
    网络攻击与防御实验二
    网络攻击与防御实验一
    C语言实验7
    C语言实验6
    C语言实验5
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358793.html
Copyright © 2020-2023  润新知