前言
这是我的第一篇文章,并没有真正补题,只是尝试着用一下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;
}
标签:吉林省,val,奇数,int,奇偶性,2024CCPC,序号,节点
From: https://www.cnblogs.com/qjsswz/p/18392409