直入主題:
學習線段樹合併.....
從名字就能看出,這個東西要合併線段樹.....
線段樹怎麼能合併呢......
暴力合就行了啊......
一次從上往下的遍歷,把所有的節點資訊暴力合併,然後就沒有然後了.....
有兩種合併方法:
一、動態開點
就是主席樹那樣的模式(可持久化了),新開乙個點記錄新的節點資訊,但是空間~巨~大~無~比~
然後可能需要刪除節點(以前的,既然合併了,就不需要舊的了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啟發式合...