随笔 - 8  文章 - 0  评论 - 1  阅读 - 1120

2024CCPC吉林省赛:B题

前言

这是我的第一篇文章,并没有真正补题,只是尝试着用一下Markdown。今天睡觉来着,明天开始发补题文章。下面是一道简单题,但我犯了一些愚蠢的错误,被这玩意卡了将近三小时,导致整场比赛自己只写了B和F两个题。好不容易写完代码,交一发直接WA on 2,多亏实力强到允许我摆烂的队友一眼找出bug,不然这题直接挂了……

唉,我怎么这么菜啊

B. Dfs Order 0.5

题意

给出一棵树,节点编号从1到n,1号节点为根。每个节点都有一定的权重。定义一个dfs序的得分为:在dfs序中的编号(以下简称为序号)为偶数的的节点的权重之和。其中1号节点序号为1。求最大得分。

解法

此题显然是树形DP,维护以每个节点为根的子树可以获得的最大得分。如果以x号节点为根的子树共有奇数个节点,不妨称x为奇数点,反之为偶数点。在x的序号分别为奇数、偶数的情况下,设以x为根的子树的最大得分分别为val[x][1]和val[x][0]。如果x的子节点全为偶数点,那么它们序号的奇偶性一定与x不同;如果x的子节点中存在奇数点,那么所有偶数子节点的序号的奇偶性可以任取[1],而对于所有奇数子节点,序号为奇数和偶数的各占一半[2]

[1] 考虑第一个走到的奇数子节点s,如果一个偶数子节点在s之前走到,那它序号的奇偶性就和s相同,也就是和根x不同;如果在s之后走到,则序号奇偶性和x相同。所以可以任取。
[2] 每走完一棵以奇数点为根的子树,序号奇偶性都会切换奇数次,也就是说,下一个走到的子节点的序号的奇偶性和当前这个一定不同。所以奇偶各占一半。

可以先假设所有奇数子节点的序号都是奇数,现在需要把其中一部分改为偶数。对于每个奇数子节点s,算出序号由奇变为偶的得分增益

tr[s] = val[s][0] - val[s][1]

把tr数组从大到小排序,取前一半就好了。
然后就做完了。最终答案就是val[1][1]。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 2e5 + 5;

int ti, n;
bool vis[N], f[N];
ll a[N], val[N][2], tr[N];
vector<int> ve[N];

bool cmp(ll t1, ll t2){
    return t1 > t2;
}

void dfs(int x){
    vis[x] = 1;
    int sz = ve[x].size();
    if(x != 1 && sz == 1){
        val[x][0] = a[x];
        return;
    }
    int pos = -1;
    bool flagji = 0, flagou = 0;
    for(int i = 0; i < sz; i++){
        int to = ve[x][i];
        if(!vis[to]){
            dfs(to);
            if(f[to]) flagou = 1;
            else flagji = 1;
        }
        else pos = i;
    }
    if(!flagji){
        for(int i = 0; i < sz; i++){
            if(i == pos) continue;
            int to = ve[x][i];
            val[x][0] += val[to][1];
            val[x][1] += val[to][0];
        }
        val[x][0] += a[x];
        return;
    }
    int p = 0;
    for(int i = 0; i < sz; i++){
        if(i == pos) continue;
        int to = ve[x][i];
        if(f[to]){
            val[x][0] += max(val[to][0], val[to][1]);
            continue;
        }
        tr[++p] = val[to][0] - val[to][1];
        val[x][0] += val[to][1];
    }
    if(p % 2) f[x] = 1;
    sort(tr + 1, tr + 1 + p, cmp);
    for(int i = 1; i <= p / 2; i++){
        val[x][0] += tr[i];
    }
    val[x][1] = val[x][0];
    if(p % 2) val[x][1] += tr[p / 2 + 1];
    val[x][0] += a[x];
}

int main(){
    scanf("%d", &ti);
    while(ti--){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%lld", &a[i]);
            val[i][0] = 0;
            val[i][1] = 0;
            f[i] = 0;
            vis[i] = 0;
            ve[i].clear();
        }
        int u, v;
        for(int i = 1; i < n; i++){
            scanf("%d%d", &u, &v);
            ve[u].push_back(v);
            ve[v].push_back(u);
        }
        if(n == 1){
            printf("0\n");
            continue;
        }
        dfs(1);
        printf("%lld\n", val[1][1]);
    }
    return 0;
}

posted on   C12AK  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示