動態開點線段樹

2022-05-24 14:09:09 字數 1712 閱讀 9154

前置芝士

眾所周知,普通線段樹空間複雜度是 \(o(n*4)\)

所以當n很大的時候,如果正常的去建一顆線段樹,開4倍n空間顯然會炸記憶體

怎麼辦呢?

這個時候,動態開點線段樹出現了。

概念​ 動態開點線段樹是一類特殊的線段樹,與普通的線段樹不同的是,每乙個節點的左右兒子不是該點編號的兩倍和兩倍加一,而是現加出來的。

​ 簡單的說,就是建立一棵「殘疾」的線段樹,上面只有詢問過的相關節點。

​ 大概長這樣(借的圖,自己畫的太醜了),理解即可,寫出來的可能不長這樣

作用​ 一般有兩種:

**更新

inline void push_up(int o)
ls[o],rs[o]代表lson和rson,以下都一樣

插入

inline void update(int &o,int l,int r,int pos,int val)

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

if(x<=mid) update(ls[o],l,mid,pos,val);

else update(rs[o],mid+1,r,pos,val);

push_up(o);//更新

}

查詢
inline int ask(int o,int l,int r,int l,int r)
和普通線段樹一樣,可維護的東西很多,在這裡就不一一枚舉了,讀者自行理解。

提示這個引數變數pos前面的取址符&是不能省略的,因為這個編號是不隨遞迴修改的定值

時間複雜度 \(o(\dfrac)~~~~q\) 為查詢次數,\(n\) 為值域

例題p1908 逆序對

題意就是求乙個序列的逆序對個數

思路相信大家都做過這題,所以就不說思路了,只是把歸併排序改為了動態開點線段樹

**有注釋的

#include using namespace std;

#define ll long long

#define lson l,mid,tree[rt].l

#define rson mid+1,r,tree[rt].r

#define ls tree[rt].l

#define rs tree[rt].r

const int mac=5e5+10;

const int inf=1e9+5;

struct node

tree[mac*32];

int sz=1;//動態分配的點的最大編號

ll query(int l,int r,int rt,int l,int r)

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

if (mid>=l) ans+=query(lson,l,r);

if (mid>1;

if (mid>=pos) update(lson,pos);//注意這裡傳進去的rt是左兒子的編號

else update(rson,pos);

tree[rt].sum=tree[ls].sum+tree[rs].sum;

}int main()

printf ("%lld\n",ans);

return 0;

}

學習筆記 動態開點線段樹

通過只開需要使用的結點以節省空間。實現過程就是把點乙個乙個往樹裡面插。建樹時遞迴進入當前結點的子結點後,若該結點為 0 即不存在,就開點。所謂開點即為把當前結點的編號設定為 tot 這樣處理下來,每個結點的編號顯然是亂序的。可以 l son 和 r son 分別記錄左右子結點的編號,然後讓它們代替普...

動態開點線段樹 學習筆記

所謂權值線段樹,就是指線段樹記憶體的是權值。好像是廢話。給出一些數,要查詢乙個區間內的數的個數。這時可以用權值線段樹,開個n n為給出的數的最大值 個點的線段樹。然後就能輕鬆的維護了當然樹狀陣列更簡單 為什麼要動態開點呢?當然是因為空間不夠啊。比如還是上面那個例子。加入給出的數的最大值為 10 並且...

旅行 樹剖,動態開點線段樹

對每一種教派開一顆線段樹,但是很明顯空間會爆,所以動態開點線段樹,所以空間複雜度降低到nlo gnnlogn nlog n,然後樹剖套線段樹,碼量稍大 include define m 200009 using namespace std intread for isdigit ch ch getc...