線段樹合併和主席樹不同的是。主席樹的節點還要依賴之前的樹結構。而線段樹合併是若干個分離的線段樹合併起來,在建立節點的時候有些不同。
按照dfs的順序處理。顯然乙個子樹內的交換只會影響該子樹,所以可以貪心得對於每個子樹決定是否交換。算到葉子節點的時候新建一顆log
loglo
g個節點的權值線段樹。合併左右兒子的時候,實際上是合併左右孩子的兩顆線段樹。不交換的話就是前面的大權值區間的個數乘以後面的小權值區間的個數;交換的話就反過來。兩者取個min就是子樹內的答案了。
空間問題:葉子節點的空間是o(n
logn
)o(nlogn)
o(nlog
n)個節點的。每次合併的時候要新建線段樹。最多向上合併o(n
)o(n)
o(n)
次。大致空間開2nl
og
n2nlogn
2nlogn
應該就ok了。
時間複雜度是均攤o(n
logn
)o(nlogn)
o(nlog
n)的。
#include
using
namespace std;
typedef
long
long ll;
const
int n =
2e5+5;
struct poi tr[n*40]
;int n, tot;
ll ans, res1, res2;
inline
intread()
while
(ch >=
'0'&& ch <=
'9')
return x * f;
}inline
void
pushup
(int k)
inline
intinsert
(int l,
int r,
int x)
int mid =
(l + r)/2
;if(x <= mid) tr[p]
.ls =
insert
(l, mid, x)
;else tr[p]
.rs =
insert
(mid +
1, r, x)
;pushup
(p);
return p;
}inline
intmerge
(int x,
int y)
inline
intinit()
return p;
}int
main()
每個聯通塊維護乙個權值線段樹。 查詢就線段樹上二分,索引回去就好了。 合併就線段樹合併。
#include
const
int n =
1e5+5;
struct poi tr[n*40]
;int fa[n]
, rt[n]
, pos[n]
, n, m, tot;
inline
intread()
while
(ch >=
'0'&& ch <=
'9')
return x * f;
}inline
intinsert
(int l,
int r,
int v)
inline
intmerge
(int x,
int y)
inline
intgetf
(int x)
inline
void
build
(int x,
int y)
}inline
intquery
(int k,
int l,
int r,
int v)
inline
char
readc()
intmain()
for(
int i =
1; i <= m;
++i)
int q =
read()
;while
(q--)}
return0;
}
筆記 線段樹合併
近期剛剛學了線段樹合併,感覺幾天後就忘了,所以寫出來方便以後複習 如有雷同,那就是我在網上借鑑的了。顧名思義,線段樹合併就是把兩棵線段樹合併到一塊,廢話,但是首先要考慮乙個問題,什麼樣的線段樹可以合併,比如一棵表示區間最大值,另一棵表示區間最小值,那這兩棵線段樹顯然不能合併,於是會發現,大部分維護區...
線段樹合併學習筆記
線段樹合併對一整個樹做完時間空間複雜度是n log nn log n nlog n的,套點其他什麼東西複雜度就上去了 動態開點的話注意 空間 樹上主席樹啟發式合併的話不 空間是兩個log的,容易被卡,比如這題 我就被卡了 悲 當然線段樹合併貌似總是可以被spl ay splay spla y啟發式合...
線段樹合併學習筆記
就是兩顆線段樹合成乙個線段樹 那合成的線段樹是適合所有線段樹嗎 當然不是,是動態開點線段樹 這裡建n個節點的時候,每個節點建一棵樹 而且要按照一定的形態建立一條鏈 就是說如果最終形態是有n個數字的樹,那你初始化的那一條鍊子一定是這顆樹上扣下來的 這樣才方便合併 最重要的操作 流程 如果x和y有一顆樹...