zoukankan      html  css  js  c++  java
  • 蔬菜(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;
    }
  • 相关阅读:
    UVA 10462 Is There A Second Way Left?(次小生成树&Prim&Kruskal)题解
    POJ 1679 The Unique MST (次小生成树)题解
    POJ 2373 Dividing the Path (单调队列优化DP)题解
    BZOJ 2709 迷宫花园
    BZOJ 1270 雷涛的小猫
    BZOJ 2834 回家的路
    BZOJ 2506 calc
    BZOJ 3124 直径
    BZOJ 4416 阶乘字符串
    BZOJ 3930 选数
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358793.html
Copyright © 2011-2022 走看看