線段樹合併

2022-08-21 20:57:09 字數 2600 閱讀 8385

應用範圍:將子樹的資訊合併給父親節點,並且權值線段樹的下標值域和節點數相近。

題目鏈結

題意:一棵樹有n個結點,每個結點都是一種顏色,每個顏色有乙個編號,求樹中每個子樹的最多的顏色編號的和。

\(1 <= n<=1e5\)

解法:線段樹合併,這個東西的時空複雜度都很玄學,姑且認為時間為\(o(nlogn)\),空間為(常數\(\times log_n\times n\)),常數一般為\(4-8\)。

#include #include using namespace std;

#define maxn 100100

#define ll long long

int n;

int fir[maxn], nxt[maxn * 2], vv[maxn * 2];

int tot = 0;

void add(int u, int v)

int cnt = 0;

int root[maxn], col[maxn];

int lz[maxn * 17 * 2], rz[maxn * 17 * 2], sum[maxn * 17 * 2];

ll ans[maxn * 17 * 2];

void pushup(int a)

if(sum[lz[a]] > sum[rz[a]])

if(sum[lz[a]] == sum[rz[a]])

return;

}int merge(int a, int b, int l, int r)

int mid = (l + r) >> 1;

lz[a] = merge(lz[a], lz[b], l, mid);

rz[a] = merge(rz[a], rz[b], mid + 1, r);

pushup(a);

return a;

}void update(int &a, int l, int r, int v)

if(mid >= v) update(lz[a], l, mid, v);

if(mid < v) update(rz[a], mid + 1, r, v);

pushup(a);

return;

}void dfs(int u, int fa)

update(root[u], 1, 100000, col[u]);

ans[u] = ans[root[u]];

}int main()

for(int i = 1; i < n; i++)

dfs(1, 0);

for(int i = 1; i <= n; i++) printf("%lld ", ans[i]);

return 0;

}

題目鏈結

注意\(ans\)要在\(dfs\)時計算,不然當前節點的\(root\)可能被父親節點繼承,然後就炸了。

#include #include using namespace std;

#define maxn 100100

#define ll long long

int n;

int fir[maxn], nxt[maxn * 2], vv[maxn * 2];

int tot = 0;

void add(int u, int v)

int cnt = 0;

int root[maxn], col[maxn];

int lz[maxn * 17 * 2], rz[maxn * 17 * 2], sum[maxn * 17 * 2];

ll ans[maxn * 17 * 2];

void pushup(int a)

if(sum[lz[a]] > sum[rz[a]])

if(sum[lz[a]] == sum[rz[a]])

return;

}int merge(int a, int b, int l, int r)

int mid = (l + r) >> 1;

lz[a] = merge(lz[a], lz[b], l, mid);

rz[a] = merge(rz[a], rz[b], mid + 1, r);

pushup(a);

return a;

}void update(int &a, int l, int r, int v)

if(mid >= v) update(lz[a], l, mid, v);

if(mid < v) update(rz[a], mid + 1, r, v);

pushup(a);

return;

}void dfs(int u, int fa)

update(root[u], 1, 100000, col[u]);

ans[u] = ans[root[u]];

}int main()

for(int i = 1; i < n; i++)

dfs(1, 0);

for(int i = 1; i <= n; i++) printf("%lld ", ans[i]);

return 0;

}

線段樹合併

做永無鄉的時候,以為是主席樹合併,後來感覺不對勁,唔。x和y是兩顆樹的根。這個演算法是從歸併演算法那引申的。實際運作的時候,考慮到了線段樹的本質 線段樹有效節點就是葉子節點。好像是句廢話。其實不是,這句話啟發我們並不需要合併一整棵樹,我們只需要處理好葉子節點,考慮把y樹合併到x上,那麼把y樹的葉子節...

線段樹合併

今天寫dsu on tree 的時候發現不會寫線段樹合併,於是滾來寫線段樹合併部落格 對於值域相同的兩個權值線段樹x xx和y yy 假設把y yy合併到x xx上 每個節點有兩種情況 其中至少有乙個節點沒有權值 x y x y x y 直接x x y x x y x x y x 0?y x x 0...

線段樹合併

某一天馬學長給我看了乙個lca的題目,然而確實是lca 樹上差分,但是僅僅有lca和樹上差分解決不了,然後我就去面向題解程式設計了。可是這個線段樹合併是個什麼東東。然而今天看書,突然看到了這個線段樹合併。就寫一下了。mmh。p4556 vani有約會 雨天的尾巴 題目背景 深繪里一直很討厭雨天。灼熱...