線段樹合併學習筆記(P4556)

2022-06-03 21:06:09 字數 2086 閱讀 4076

直入主題:

學習線段樹合併.....

從名字就能看出,這個東西要合併線段樹.....

線段樹怎麼能合併呢......

暴力合就行了啊......

一次從上往下的遍歷,把所有的節點資訊暴力合併,然後就沒有然後了.....

有兩種合併方法:

一、動態開點

就是主席樹那樣的模式(可持久化了),新開乙個點記錄新的節點資訊,但是空間~巨~大~無~比~

然後可能需要刪除節點(以前的,既然合併了,就不需要舊的了233....)

二、靜態開點(口胡的)

像啟發式合併那樣,直接把a的資訊全加到b上(雖然沒有任何啟發式),但是可能破壞a樹的形態

於是放一發模板題(本蒻第一次封裝結構體233)

(感覺就是主席樹233)

首先,思路樹上差分,但是具體怎麼玩呢?

乙個暴力的思路:

對於每乙個給定的補給點,建一棵權值線段樹,其他的點也有線段樹但是是空樹,然後在差分的時候直接把所有的點給合併起來,最後統計答案。

線段樹維護的是最值。

注意的是:差分:a+1,b+1,lca-1,lca的父節點+1,這個父節點是為了消除向上的影響,只維護路徑上的值。

注釋在**:

#includeusing

namespace

std;

const

int maxn=1e6+10

;int

n,m;

struct

edge

e[maxn];

inthead[maxn],cnt;

inline

void addedge(int

from,int

to)int

dep[maxn];

int f[maxn][40

];int dfs(int u,int

fa)}

intrt[maxn];

struct

segtree//第一次封裝結構體

else

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

r)

int mid=l+r>>1

; lc[a]=merge(lc[a],lc[b],l,mid);//向下合併

rc[a]=merge(rc[a],rc[b],mid+1

,r);//向下合併

pushup(a);//記得更新

return

a; }

void insert(int &x,int l,int r,int p,int

k)

int mid=l+r>>1

;

if(p<=mid)insert(lc[x],l,mid,p,k);

else insert(rc[x],mid+1

,r,p,k);

pushup(x);

}}t;int lca(int a,int

b)//平淡無奇的lca

if(a==b)

return

a;

for(int i=20;i>=0;i--)

}return f[a][0];}

intans[maxn];

void dfsans(int u,int

fa) ans[u]=t.id[rt[u]];//更新答案

if(t.ma[rt[u]]==0

) ans[u]=0

;//記得特判0的情況

}int

main()

dfs(

1,0);

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

}for(int i=1;i<=m;i++)

dfsans(

1,0);

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

printf(

"%d\n

",ans[i]);

return0;

}

(完)

P4556 線段樹合併,差分

線段樹合併 差分 對於每次修改操作 u,v u,v u,v 我們給u,v u,vu,v節點打上 1 1 1的標記,給lca u,v lca u,v lca u,v f l ca u v f lca u,v f lca u,v 打上 1的標記 最後計算答案的時候,dfs dfsdf s一遍,將子樹內的...

P4556 雨天的尾巴 線段樹合併

題目背景 深繪里一直很討厭雨天。灼熱的天氣穿透了前半個夏天,後來一場大雨和隨之而來的洪水,澆滅了一切。雖然深繪里家鄉的小村落對洪水有著頑固的抵抗力,但也倒了幾座老房子,幾棵老樹被連根拔起,以及田地裡的糧食被弄得一片狼藉。無奈的深繪里和村民們只好等待救濟糧來維生。不過救濟糧的發放方式很特別。題目描述 ...

線段樹合併學習筆記

線段樹合併對一整個樹做完時間空間複雜度是n log nn log n nlog n的,套點其他什麼東西複雜度就上去了 動態開點的話注意 空間 樹上主席樹啟發式合併的話不 空間是兩個log的,容易被卡,比如這題 我就被卡了 悲 當然線段樹合併貌似總是可以被spl ay splay spla y啟發式合...