線段樹合併

2021-09-26 14:54:31 字數 3351 閱讀 1748

某一天馬學長給我看了乙個lca的題目,然而確實是lca+樹上差分,但是僅僅有lca和樹上差分解決不了,然後我就去面向題解程式設計了。

可是這個線段樹合併是個什麼東東。。。

然而今天看書,突然看到了這個線段樹合併。

就寫一下了。

%mmh。

p4556 [vani有約會]雨天的尾巴:

題目背景

深繪里一直很討厭雨天。

灼熱的天氣穿透了前半個夏天,後來一場大雨和隨之而來的洪水,澆滅了一切。

雖然深繪里家鄉的小村落對洪水有著頑固的抵抗力,但也倒了幾座老房子,幾棵老樹被連根拔起,以及田地裡的糧食被弄得一片狼藉。

無奈的深繪里和村民們只好等待救濟糧來維生。

不過救濟糧的發放方式很特別。

題目描述

首先村落裡的一共有n座房屋,並形成乙個樹狀結構。然後救濟糧分m次發放,每次選擇兩個房屋(x,y),然後對於x到y的路徑上(含x和y)每座房子裡發放一袋z型別的救濟糧。

然後深繪里想知道,當所有的救濟糧發放完畢後,每座房子裡存放的最多的是哪種救濟糧。

輸入格式

第一行兩個正整數n,m,含義如題目所示。

接下來n-1行,每行兩個數(a,b),表示(a,b)間有一條邊。

再接下來m行,每行三個數(x,y,z),含義如題目所示。

輸出格式

n行,第i行乙個整數,表示第i座房屋裡存放的最多的是哪種救濟糧,如果有多種救濟糧存放次數一樣,輸出編號最小的。

如果某座房屋裡沒有救濟糧,則對應一行輸出0。

輸入輸出樣例

輸入 #1 複製

5 31 2

3 13 4

5 32 3 3

1 5 2

3 3 3

輸出 #1 複製23

302說明/提示

對於20%的資料,1 <= n, m <= 100

對於50%的資料,1 <= n, m <= 2000

對於100%的資料,1 <= n, m <= 100000, 1 <= a, b, x, y <= n, 1 <= z <= 100000

vani

#include

#include

#include

#include

#include

#include

#include

#define ll long long

#define llu unsigned ll

using

namespace std;

const

int mod=

1e9+7;

const

int inf=

0x3f3f3f3f

;const ll lnf=

0x3f3f3f3f3f3f3f3f

;const

int maxn=

100100

;struct node

t[maxn*20*

4];int f[maxn][20

],root[maxn]

,d[maxn]

,ans[maxn]

;int head[maxn]

,ver[maxn*2]

,nt[maxn*2]

;int xx[maxn]

,yy[maxn]

,zz[maxn]

,b[maxn]

;int tot=

1,n,m,tt,cnt=

0,pm;

void

add(

int x,

int y)

void

bfs(

void)}

}int

lca(

int x,

int y)

intbuild

(void

)void

pushup

(int p)

void

_insert

(int p,

int l,

int r,

int pos,

int val)

int mid=

(l+r)

>>1;

if(pos<=mid)

else

pushup

(p);

}int

_merge

(int p,

int q,

int l,

int r)

int mid=

(l+r)

>>1;

t[p]

.lc=

_merge

(t[p]

.lc,t[q]

.lc,l,mid)

; t[p]

.rc=

_merge

(t[p]

.rc,t[q]

.rc,mid+

1,r)

;pushup

(p);

return p;

}void

dfs(

int x,

int fa)

ans[x]

=t[root[x]

].pos;

}int

main

(void

)for

(int i=

1;i<=m;i++

)scanf

("%d%d%d"

,&xx[i]

,&yy[i]

,&zz[i]

),b[i]

=zz[i]

;bfs()

;sort

(b+1

,b+m+1)

; pm=

unique

(b+1

,b+m+1)

-(b+1)

;for

(int i=

1;i<=n;i++

) root[i]

=build()

;for

(int i=

1;i<=m;i++

) zz[i]

=lower_bound

(b+1

,b+pm+

1,zz[i]

)-b;

for(

int i=

1;i<=m;i++

)dfs(1

,0);

for(

int i=

1;i<=n;i++

)printf

("%d\n"

,b[ans[i]])

;return0;

}

線段樹合併

做永無鄉的時候,以為是主席樹合併,後來感覺不對勁,唔。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...

線段樹合併

線段樹合併雖說是比較基礎的內容,且我一直都知道大概的實現方式,但直到最近我才正式去寫過一次,我真的太弱了啊。下面從暴力合併開始,依次介紹幾種線段樹合併的方式。直接暴力摳出線段樹中的元素,然後暴力合併。總合併時間複雜度應為 o n 2logn 應該算是暴力合併的一種優化。即,每次合併時選取較小的一棵線...