題目鏈接:https://ac.nowcoder.com/acm/contest/6037/F
題意:給一棵樹有n個節點,根節點爲1。每個點有一個顏色,並且有一個權值,爲當前這個節點顏色的數量。
對每個點輸出,當前點以及子樹中的最大匹配數。當且僅當顏色不同可以匹配。
思路:記錄每個子樹的所有顏色數量sum和以及最多的那個種類的顏色個數max,如果max大於sum/2,那麼說明
最多隻能有sum - max對能夠匹配,否則的話說明可以將其都兩兩配對。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fi first
#define se second
#define ls rt << 1
#define rs rt << 1|1
#define po pop_back
#define pb push_back
#define mk make_pair
#define lson l, mid, ls
#define rson mid + 1, r, rs
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ull unsigned long long
#define pdd pair<double, double>
const int mod = 1e9 + 9;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
int c[maxn], num[maxn], sz[maxn], son[maxn], sum[maxn], cnt[maxn], ans[maxn], Max, Son;
vector<int> e[maxn];
void dfs(int u, int fa) //統計重兒子信息
{
sz[u] = 1;
sum[u] = num[u];
for(auto v : e[u])
{
if(v == fa) continue;
dfs(v, u);
sz[u] += sz[v];
sum[u] += sum[v];
if(sz[son[u]] < sz[v]) son[u] = v;
}
}
void calc(int u, int fa, int val)
{
cnt[c[u]] += val * num[u];
if(cnt[c[u]] > Max) Max = cnt[c[u]];
for(auto v : e[u])
{
if(v == fa || v == Son) continue;
calc(v, u, val);
}
}
void dfs2(int u, int fa, int op) // 0輕鏈 1重鏈
{
for(auto v : e[u])
{
if(v == fa || v == son[u]) continue;
dfs2(v, u, 0);
}
if(son[u]) //重兒子計算貢獻 不消除
dfs2(son[u], u, 1), Son = son[u];
calc(u, fa, 1), Son = 0;
if(Max > sum[u] / 2) ans[u] = sum[u] - Max;
else ans[u] = sum[u] / 2;
if(!op) calc(u, fa, -1), Max = 0; //消除貢獻
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i < n; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
e[u].pb(v), e[v].pb(u);
}
for(int i = 1; i <= n; ++i) scanf("%d%d", &c[i], &num[i]);
dfs(1, 0);
dfs2(1, 0, 0);
for(int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
return 0;
}