CF600E Lomsat gelral 權值線段樹題解
阿新 • • 發佈:2021-07-16
前言
其實就是一道線段樹合併的板子,因為機房要求寫就寫了。
題意
問 \(1\sim n\) 的子樹中各個子樹的眾數和。
分析
其實,一般如果要求各個子樹的某個東西,我們一般都是考慮 線段樹合併/dsu on tree/dfn+其他資料結構(可能還有其他做法,只不過我太菜了不會),所以我才會說顯然。
考慮將每個點都建一棵權值線段樹,跑一次 \(dfs\), 將子樹 合併,然後線段樹中維護我們想要的東西,在這道題中就是數字出現的 最大次數 和 眾數和。
關於時間複雜度:對於每次底層的合併,都會使兩個數綁成一塊,那最多進行 \(n\) 次,每次跑到底層需要 \(log_2(n)\),則時間複雜度:\(\mathcal {O}(nlog_2(n))\)
關於左右區間合併,若出現的次數相等,貢獻為兩邊相加,否則為次數大的那個。
Code
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <vector> #define LL long long using namespace std; const int MAXN = 1e5 + 5; struct Segment_Tree { int L, R, Max; LL Sum; }tree[MAXN * 65]; int n, a[MAXN], tot, root[MAXN]; LL ans[MAXN]; vector <int> v[MAXN]; int max_(int x, int y) { return x > y ? x : y; } int add(int p, int x, int l, int r) { if(!p) p = ++ tot; if(l == r) { tree[p].Max = 1; tree[p].Sum = x; return p; } int mid = (l + r) >> 1; if(x <= mid) tree[p].L = add(tree[p].L, x, l, mid); else tree[p].R = add(tree[p].R, x, mid + 1, r); if(tree[tree[p].L].Max == tree[tree[p].R].Max) tree[p].Sum = tree[tree[p].L].Sum + tree[tree[p].R].Sum, tree[p].Max = max_(tree[tree[p].L].Max, tree[tree[p].R].Max); else tree[p].Max = max_(tree[tree[p].L].Max, tree[tree[p].R].Max), tree[p].Sum = tree[tree[p].L].Max >= tree[tree[p].R].Max ? tree[tree[p].L].Sum : tree[tree[p].R].Sum; return p; } int Merge(int p, int q, int l, int r) { if(!p) return q; if(!q) return p; if(l == r) { tree[p].Max += tree[q].Max; tree[p].Sum = tree[q].Sum; return p; } int mid = (l + r) >> 1; tree[p].L = Merge(tree[p].L, tree[q].L, l, mid); tree[p].R = Merge(tree[p].R, tree[q].R, mid + 1, r); if(tree[tree[p].L].Max == tree[tree[p].R].Max) tree[p].Sum = tree[tree[p].L].Sum + tree[tree[p].R].Sum, tree[p].Max = max_(tree[tree[p].L].Max, tree[tree[p].R].Max); else tree[p].Max = max_(tree[tree[p].L].Max, tree[tree[p].R].Max), tree[p].Sum = tree[tree[p].L].Max >= tree[tree[p].R].Max ? tree[tree[p].L].Sum : tree[tree[p].R].Sum; // printf("%d %d %d %lld\n", l, r, tree[p].Max, tree[p].Sum); return p; } void dfs(int x, int fa) { for(unsigned int i = 0; i < v[x].size(); i ++) { int y = v[x][i]; if(y == fa) continue; dfs(y, x); root[x] = Merge(root[x], root[y], 1, n); } ans[x] = tree[root[x]].Sum; } int main() { int x, y; scanf("%d", &n); tot = n; for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), root[i] = i, root[i] = add(root[i], a[i], 1, n); for(int i = 1; i < n; i ++) { scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } dfs(1, -1); for(int i = 1; i <= n; i ++) printf("%lld ", ans[i]); return 0; }