指標 動態開點 合併線段樹

2022-03-16 14:34:48 字數 1591 閱讀 4402

乙個知識點不在一道題裡說是沒有靈魂的

線段樹是用來處理區間資訊的咯

但是往往因為需要4倍空間讓許多人退卻,而動態開點的線段樹就非常

彷彿只用2倍就可以咯

指標儲存位置,即節點資訊,是很舒適的,所以用指標動態開點就更

《永無鄉題面》

這個題哈,我剛開始學線段樹合併時慣例懵,

而且我發現……網上的題解有簡短甚至偷懶的,於是我很廢了,去問神犇

下面就是,比較清楚的題解

首先我們會發現這個題像乙個,圖論?

但是並不是,因為他問的並不是圖的問題(像最短路?),而是聯通性,和排名下標,就不用建圖

so,分開考慮

1.聯通性:dfs的是想岔了,冰茶几(並查集)適合維護這個----->  o(logn)

2.排名下標:

平衡樹,不會合併(哭笑不得)

線段樹,不錯,如果用權值線段樹就可以查排名咯

權值線段樹,類似於桶排序,用下標存數,每個節點存的是從l到r的數個數

這樣乙個數的排名就是左面的節點中個數加一

自帶二分,非常快

然後就是合併的操作(這個去專門學也好),用不空的節點直接代替空的節點,把不空的公共節點值相加

另外再說一句,我用指標的new函式了,所以慢死,我從大佬們處得知指標要與結構體陣列一塊用,達到既美觀直觀又快的效果

結果:

#include#include#include#define n 100010

using namespace std;

struct xds

};xds *root[n];

int itd[n];

void build(xds *&rt,int l,int r)

void add(xds *&rt,int l,int r,int v)

int mid=(l+r)/2;

if(v<=mid)

else

if(rt->lid!=null)

rt->dat+=rt->lid->dat;

if(rt->rid!=null)

rt->dat+=rt->rid->dat;

}inline void add(xds *&rt,int v)

int kth(xds *rt,int k)

if(rt->lid!=null&&rt->lid->dat>=k)

else if(rt->rid!=null)

}return n;

}xds* mmerge(int l,int r,xds *a,xds *b)

int fa[n];

int faind(int x)

return fa[x];

}int isn,bn;

void prerun()

}void unity(int x,int y)

}int main()

char ch[3];

scanf("%d",&a);

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

else

}return 0;

}

線段樹動態開點

為了降低權值線段樹的空間複雜度,可以不直接建出整棵線段樹的結構,而是在最初只建立乙個根節點,當需要訪問某棵為建立的子樹的時候,再建立代表這個子樹的節點。動態開點的線段樹用變數記錄左右節點的編號。值域為1 n的動態開點線段樹在m次單點修改後,節點規模為o mlogn 例題 p1908 逆序對 這題n最...

線段樹 動態開點

在一些計數問題中,線段樹用於維護值域 一段權值範圍 這樣的線段樹也稱為權值線段樹。為了降低空間複雜度,我們可以不建出整棵線段樹的結構,而是在最初只建立乙個根節點,代表整個區間,當需要訪問線段樹的某棵子樹 某個子區間 時,再建立代表這個子區間的節點。採用這種方法維護的線段樹稱為動態開點的線段樹。動態開...

BZOJ 4756 線段樹合併(線段樹)

思路 1.最裸的線段樹合併 2.我們可以觀察到子樹求乙個東西 那我們直接dfs序好了 入隊的時候統計一下有多少比他大的 出的時候統計一下 減一下 搞定 線段樹合併 by siriusren include include include using namespace std const int n...