學習筆記 線段樹合併

2022-04-29 23:39:11 字數 2766 閱讀 8229

分析:線段樹合併人生第一題。

網上的題解我都沒看懂……我自己講一下好了

線段樹合併就是把兩棵權值線段樹合併到一棵

那怎麼合併呢?

假設有這麼兩棵樹:

乙個結點代表一段值域區間有幾個數,那麼可以看出合併後應該是這樣的

然後具體步驟就是找到乙個結點,如果乙個結點一棵樹上有一棵樹上沒有,那麼直

接返回那個結點的編號,否則兩個值域的和相加,遞迴至左兒子和右兒子

每次合併的複雜度為兩棵線段樹的點數相加

這道題可以算出左兒子的逆序對個數,右兒子的逆序對個數,然後求出 \((x,y)\) 的對數, $x\in $ 左兒子, $y\in $ 右兒子

每次記錄一下 \(sum\),在每次合併的時候 \(sum[lson[x]]\times sum[rson[y]]\) 和 \(sum[rson[x]]\times sum[lson[y]]\) 中取個最小值算進答案的貢獻就可以了(不懂可以自己畫圖或看**理解一下)

\(code\ below:\)

#include #define ll long long

using namespace std;

const int maxn=200000+10;

int n,l[maxn*24],r[maxn*24],sum[maxn*24],cnt;

ll ans,num1,num2;

inline int read()

while(isdigit(ch))

return (f==1)?x:-x;

}void update(int &now,int l,int r,int x)

void merge(int &x,int y)

sum[x]+=sum[y];

num1+=(ll)sum[r[x]]*sum[l[y]];

num2+=(ll)sum[l[x]]*sum[r[y]];

merge(l[x],l[y]);

merge(r[x],r[y]);

}void dfs(int &x)

else update(x,1,n,val);

}int main()

分析:考慮樹上查分。這次權值線段樹維護最多救濟糧的編號 \(val\) 和 最多救濟糧的個數 \(sum\),在葉子節點更新一下,最後 \(pushup\) 一下

\(code\ below:\)

#include using namespace std;

const int maxn=100000+10;

const int size=100000;

int n,m,ans[maxn],rt[maxn],l[maxn*80],r[maxn*80],val[maxn*80],sum[maxn*80],cnt;

int head[maxn],to[maxn<<1],nxt[maxn<<1],tot;

int top[maxn],dep[maxn],siz[maxn],son[maxn],fa[maxn];

inline int read()

while(isdigit(ch))

return (f==1)?x:-x;

}inline void add(int x,int y)

void dfs1(int x,int f)

void pushup(int now)

void merge(int &x,int y,int l,int r)

if(l == r)

int mid=l+r>>1;

merge(l[x],l[y],l,mid);

merge(r[x],r[y],mid+1,r);

pushup(x);

}void dfs(int x,int f)

ans[x]=val[rt[x]];

}int main()

while(isdigit(ch))

return (f==1)?x:-x;

}inline void add(int x,int y)

void pushup(int now)

void update(int &now,int l,int r,int x)

if(x <= mid) update(lson,l,mid,x);

else update(rson,mid+1,r,x);

pushup(now);

}void merge(int &x,int y,int l,int r)

if(l == r)

merge(l[x],l[y],l,mid);

merge(r[x],r[y],mid+1,r);

pushup(x);

}void dfs(int x,int f)

an[x]=ans[rt[x]];

}signed main()

{ n=read();

int x,y;

for(int i=1;i<=n;i++) a[i]=read();

for(int i=1;i搞了乙個下午線段樹合併,還是很有成就感滴!

線段樹合併學習筆記

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

線段樹合併學習筆記

就是兩顆線段樹合成乙個線段樹 那合成的線段樹是適合所有線段樹嗎 當然不是,是動態開點線段樹 這裡建n個節點的時候,每個節點建一棵樹 而且要按照一定的形態建立一條鏈 就是說如果最終形態是有n個數字的樹,那你初始化的那一條鍊子一定是這顆樹上扣下來的 這樣才方便合併 最重要的操作 流程 如果x和y有一顆樹...

線段樹合併 學習筆記

權值線段樹 動態開點線段樹 有時候我們需要對權值線段樹進行合併操作。然後就用到了線段樹合併。一般是有很多棵線段樹,然後需要將其中的兩棵合併起來。其實方法很簡單呢。就是分三種情況討論一下。假設現在要將線段樹a和線段樹b合併。並且a成為合併之後的線段樹。如果a有當前子樹,而b沒有,那麼返回a的當前子樹 ...