CodeForces-600E Lomsat gelral DSU on Tree 模板题
CodeForces-600E Lomsat gelral DSU on Tree 模板题
题意
- 有一颗\(n\)个结点,以1为根的有根树
- 每个结点有一种颜色,颜色以编号表示,\(i\)号结点的颜色编号为\(c_i\)
- 如果一种颜色以\(x\)为根的子树内出现最多,称其为\(x\)为根的子树中占主导地位。显然同一个子树中可能有多种颜色占主导地位。
- 求出\(1-n\)的子树中,占主导地位的颜色的编号和
\[1\leq n \leq 10^5,c_i \leq n
\]
分析
典型的启发式合并题(DSU on Tree)
核心思想:利用重链剖分的性质优化子树贡献的计算
来解决一类不带修改的子树查询问题
- 预处理重儿子
- dfs所有轻儿子,并清空贡献
- dfs重儿子,不清空贡献
- 暴力合并除了重儿子以外的贡献
代码
int fa[maxn],son[maxn],dep[maxn],siz[maxn],top[maxn];
vector<int> e[maxn];
ll a[maxn],cnt[maxn],ans[maxn];
ll sum;
int mx,Son;
void dfs1(int u){
siz[u] = 1;
for(auto v:e[u]){
if(v == fa[u]) continue;
dep[v] = dep[u] + 1;
fa[v] = u;
dfs1(v);
siz[u] += siz[v];
if(siz[v] > siz[son[u]])
son[u] = v;
}
}
void add(int x,int val){
cnt[a[x]] += val;
if(cnt[a[x]] > mx) mx = cnt[a[x]],sum = a[x];
else if(cnt[a[x]] == mx) sum += a[x];
for(auto v:e[x]){
if(v == fa[x] || v == Son) continue;
add(v,val);
}
}
void dfs(int x,int op){
for(auto v:e[x]){
if(v == fa[x]) continue;
if(v != son[x]) dfs(v,0);
}
if(son[x]) dfs(son[x],1),Son = son[x];
add(x,1);
Son = 0;
ans[x] = sum;
if(!op) add(x,-1),sum = 0,mx = 0;
}
int main(){
int n = readint();
for(int i = 1;i <= n;i++)
a[i] = readint();
for(int i = 1;i < n;i++){
int u = readint();
int v = readint();
e[u].pb(v);
e[v].pb(u);
}
dfs1(1);
dfs(1,0);
for(int i = 1;i <= n;i++)
cout << ans[i] << ' ';
}