第十八届西电程序设计竞赛-D

第十八届西电程序设计竞赛-D

九月 06, 2020

D.双倍快乐

题意

给出一个n个点的树(n-1条边)

每个点有一个权值val[i]

每条边有一个属性0/1

定义一个点的快乐值为它的子节点的快乐值+它自身的权值

当且仅当一个点既有1又有0 的边时它自身的权值会翻倍

于是它的快乐值=它的子节点的快乐值+它自身的权值×2

现在最多改变一个边的属性 0变1 ,1变0

问所有点的快乐值和最大是多少

题解

注意到题目中翻倍的是自身权值 而不是它的快乐值

所以可以将翻倍的贡献独立出来计算

将一个点对总的贡献值看作

(它的子节点贡献+它自身的权值) 和 (修改某边使节点权值翻倍的贡献)

对于前者可直接通过dfs求得

对于后者则枚举修改那一条边能产生的贡献最大

注意改变一条边的属性可能会使两个点翻倍

观察发现 对于一个点i若改变一条边能使得它自身的权值 翻倍

那么它翻倍部分(即多加了val[i])对总快乐值的贡献为deep[i]×val[i]

(因为它的权值将会作为父节点快乐值的一部分向上传递)

于是枚举修改边 计算翻倍产生贡献最大的 更新答案

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define Turnoff std::ios::sync_with_stdio(false)
const ll Max=1e5+5;
const double Pi=acos(-1);
const ll mod=1e9+7;
/*
*/
ll val[Max],d[Max];
bool doub[Max],can[Max];
int cnt[2][Max],deep[Max];
vector<pair<int,int> >mp[Max];

void dfs_val(int now,int fa){
for(auto i:mp[now]){
if(fa==i.first)continue;
//deep[i.first]=deep[now]+1;
dfs_val(i.first,now);
val[now]+=val[i.first];
}
}
void dfs_deep(int now,int fa){
for(auto i:mp[now]){
if(fa==i.first)continue;
deep[i.first]=deep[now]+1;
dfs_deep(i.first,now);
//val[now]+=val[i.first];
}
}
int main(){
//Turnoff;
int n;cin>>n;
for(int i=1;i<=n;i++){
cin>>d[i];
val[i]=d[i];
}
for(int i=1;i<n;i++){
int u,v,w;
cin>>u>>v>>w;
mp[u].push_back({v,w});
mp[v].push_back({u,w});
}
for(int i=1;i<=n;i++){
int cnt1=0,cnt0=0;
for(auto edge:mp[i]){
if(edge.second)cnt[1][i]++;
else cnt[0][i]++;
}
}
deep[1]=1;dfs_deep(1,0);ll ans=0,change=0;
for(int i=1;i<=n;i++){
if(cnt[0][i]&&cnt[1][i])val[i]*=2;
}
dfs_val(1,0);
for(int i=1;i<=n;i++)ans+=val[i];
for(int i=1;i<=n;i++){
for(auto edge:mp[i]){
ll temp=0;int to=edge.first;
if(edge.second){
temp-=(cnt[1][i]&&cnt[0][i])*d[i]*deep[i];
temp-=(cnt[1][to]&&cnt[0][to])*d[to]*deep[to];
cnt[1][i]--;cnt[0][i]++;
cnt[1][to]--;
cnt[0][to]++;
temp+=(cnt[1][i]&&cnt[0][i])*d[i]*deep[i];
temp+=(cnt[1][to]&&cnt[0][to])*d[to]*deep[to];
cnt[1][i]++;cnt[0][i]--;
cnt[1][to]++;
cnt[0][to]--;
}
else{
temp-=(cnt[1][i]&&cnt[0][i])*d[i]*deep[i];
temp-=(cnt[1][to]&&cnt[0][to])*d[to]*deep[to];
cnt[0][i]--;cnt[1][i]++;
cnt[0][to]--;
cnt[1][to]++;
temp+=(cnt[1][i]&&cnt[0][i])*d[i]*deep[i];
temp+=(cnt[1][to]&&cnt[0][to])*d[to]*deep[to];
cnt[0][i]++;cnt[1][i]--;
cnt[0][to]++;
cnt[1][to]--;
}
change=max(change,temp);
}
}
//cout<<ans<<" "<<change<<endl;
cout<<ans+change<<endl;
}