写在前面
大多数人写的换根 d p dp dp,于是便有了这篇题解。
题目大意:
一颗树,每个点或黑或白,问所有包含这个点的链最大的 c n t 白 − c n t 黑 cnt白-cnt黑 cnt白−cnt黑。
思路:
一个点相连的有它的子和他的父。
可以分开考虑和子相连还是和父相连。
第一遍
d
f
s
dfs
dfs由子更新父(和子相连)
int dep[N]; // 记录深度
void dfs(int now,int last){
if(col[now]==1) ans[now]=1; // cnt白-cnt黑
else ans[now]=-1;
dep[now]=dep[last]+1;
for(auto it:ve[now]){
if(it!=last){
dfs(it,now);
if(ans[now]+ans[it]>ans[now]){ // 尝试更新
ans[now]=ans[now]+ans[it];
ll s=(ll)now*(ll)1000000+(ll)it; // 记录now->it连了边
mp[s]=1;
}
}
}
}
注意一点:
这里配合
m
a
p
map
map可以记录两点之间存在边(点的编号在
2
e
5
2e5
2e5以内这样不会有冲突)
其作用在
b
f
s
bfs
bfs上。
ll s=(ll)now*(ll)1000000+(ll)it;
第二遍
b
f
s
bfs
bfs由父更新子(和父相连)
这里要注意一点。
1
1
1在第一遍
d
f
s
dfs
dfs中已经和
3
3
3连边,也就是说
1
1
1的答案已经包含
3
3
3故更新是
ans[it]=max(ans[it],ans[now]); // now(1), it(3)
2 2 2在第一遍 d f s dfs dfs中未和 3 3 3连边,也就是说 2 2 2的答案不包含 3 3 3。故更新是
ans[it]=max(ans[it],ans[it]+ans[now]); // now(2), it(3)
判断连边直接查
m
a
p
map
map即可。
int flag[N];
void bfs(int u){
queue<int> p; p.push(u); flag[u]=1;
while(!p.empty()){
int now=p.front(); p.pop();
for(auto it:ve[now]){
if(dep[it]>dep[now]){ // 保证父更新子
ll s=(ll)now*(ll)1000000+(ll)it;
if(!mp[s]){ // 没有连边
ans[it]=max(ans[it],ans[it]+ans[now]);
}
else{
ans[it]=max(ans[it],ans[now]);
}
}
if(!flag[it]){
p.push(it);
flag[it]=1;
}
}
}
}
Code
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
int n,col[N],ans[N];
vector<int> ve[N];
map<ll,int> mp;
int dep[N];
void dfs(int now,int last){
if(col[now]==1) ans[now]=1;
else ans[now]=-1;
dep[now]=dep[last]+1;
for(auto it:ve[now]){
if(it!=last){
dfs(it,now);
if(ans[now]+ans[it]>ans[now]){
ans[now]=ans[now]+ans[it];
ll s=(ll)now*(ll)1000000+(ll)it;
mp[s]=1;
}
}
}
}
int flag[N];
void bfs(int u){
queue<int> p; p.push(u); flag[u]=1;
while(!p.empty()){
int now=p.front(); p.pop();
for(auto it:ve[now]){
if(dep[it]>dep[now]){
ll s=(ll)now*(ll)1000000+(ll)it;
if(!mp[s]){
ans[it]=max(ans[it],ans[it]+ans[now]);
}
else{
ans[it]=max(ans[it],ans[now]);
}
}
if(!flag[it]){
p.push(it);
flag[it]=1;
}
}
}
}
int main(){
guo312;
cin>>n;
for(int i=1;i<=n;i++){
cin>>col[i];
}
for(int i=1;i<n;i++){
int u,v; cin>>u>>v;
ve[u].push_back(v);
ve[v].push_back(u);
}
dfs(1,0); bfs(1);
for(int i=1;i<=n;i++){
cout<<ans[i]<<" ";
}
return 0;
}