该算法的全称叫做:动态开点权值线段树合并.一般用来解决不好维护的子树信息.
一般来讲,线段树合并都是指的权值线段树合并.目前还没见到过非权值线段树的合并.
题目大意:
给你一颗树,每个点上有一个权值 v a l i val_i vali.现在问你,对于每一颗子树,它的出现次数最多的权值的和为多少(有多个出现次数最多的,都应算上). n ≤ 1 e 5 n \leq 1e5 n≤1e5
题目思路:
两种解法吧,1.dsu on tree. 2.线段树合并.基本都能当板子题使用了.
学过主席树会觉得这个东西没有违和感. 动态开n颗线段树,dfs的时候合并子树的线段树.然后线段树中查询答案就好了.
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
关键代码:如何合并线段树?
// 将以b为根的子线段树合并到a上.
int mer (int u , int v , int l , int r)
{
if (!u) return v;
if (!v) return u;
if (l == r){
mx[u] += mx[v];
res[u] = l;
return u;
}
ls[u] = mer (ls[u] , ls[v] , l , mid);
rs[u] = mer (rs[u] , rs[v] , mid + 1 , r);
pushup(u);
return u;
}
注:
若u,v其中一个是空节点,那么直接将非空的节点返回给父节点连上.
若到了叶子节点,将v的信息合并到u上.
否则就递归的合并左右子树,将返回回来的节点连在u的左右子树上.
AC代码:
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define mid ((l + r) >> 1)
using namespace std;
const int maxn = 1e5 + 4;
int mx[maxn << 5] , ls[maxn << 5] , rs[maxn << 5] , rt[maxn] , tot;
ll res[maxn << 5];
void pushup (int t)
{
int tl = ls[t] , tr = rs[t];
mx[t] = max (mx[tl] , mx[tr]);
if (mx[tl] == mx[tr]) res[t] = res[tl] + res[tr];
else res[t] = (mx[tl] > mx[tr] ? res[tl] : res[tr]);
}
int add (int l , int r , int t , int p)
{
int now = ++tot;
ls[now] = ls[t];
rs[now] = rs[t];
if (l == r) {
mx[now]++;
res[now] = p;
return now;
}
if (p <= mid) ls[now] = add(l , mid , ls[now] , p);
else rs[now] = add (mid + 1 , r , rs[now] , p);
pushup(now);
return now;
}
int mer (int u , int v , int l , int r)
{
if (!u) return v;
if (!v) return u;
if (l == r){
mx[u] += mx[v];
res[u] = l;
return u;
}
ls[u] = mer (ls[u] , ls[v] , l , mid);
rs[u] = mer (rs[u] , rs[v] , mid + 1 , r);
pushup(u);
return u;
}
vector<int> E[maxn];
ll ans[maxn];
int a[maxn] , n;
void dfs (int u , int fa)
{
rt[u] = add(1 , n , rt[0] , a[u]);
for (auto v : E[u]){
if (v == fa) continue;
dfs (v , u);
mer(rt[u] , rt[v] , 1 , n);
}
ans[u] = res[rt[u]];
}
int main()
{
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n ; i++){
cin >> a[i];
}
for (int i = 1; i < n ; i++){
int x , y; cin >> x >> y;
E[x].pb (y);
E[y].pb (x);
}
dfs (1 , 0);
for (int i = 1; i <= n ; i++)
cout << ans[i] << " ";
cout << endl;
return 0;
}