挖坑 GSS GSS7 樹鏈剖分中的最大子段和

2021-09-13 18:59:06 字數 3429 閱讀 8476

can you answer these queries?

gss系列是spoj出品的一套資料結構好毒瘤題,主要以線段樹、平衡樹和樹鏈剖分為背景,進行了一些操作的魔改,使得難度遠超模板題,但對於思維有極大的提公升。

所以我會選擇一些在我能力範圍內的題挖坑選講,構成乙個gss系列。至於剩下那些,等我成為巨佬弄懂了再說吧。

原題傳送門(洛谷)

gss1:區間最大子段和。(題解:csdn, 個人部落格)

樹鏈剖分

給定一棵樹,動態修改兩點路徑上的點權,查詢兩點路徑上的最大子段和。

最大子段和又雙叒叕公升級啦!!

這次變成了樹上修改和查詢。

其實樹鏈剖分的精髓部分就在於線段樹以及最後跳鏈的部分,那麼我們就從這兩個地方入手。線段樹上的最大子段和並沒有什麼特殊的地方,直接用gss1的做法即可。主要難點在於跳鏈查詢。

我們會發現,跳鏈的時候區間不一定是連續的,那麼最後對答案的合併就是乙個較大的問題。再進一步思考,會發現由於查詢的是最大子段和,所以合併的時候要是把左右區間搞反,就會直接掛掉。所以我們考慮在跳鏈的時候分類討論。

我們設兩個變數分別記錄上一次跳x

xx和上一次跳y

yy的結果,都作為當前跳鏈的右區間,然後查詢相應的重鏈上的結果,作為左區間,最後合併到x

xx和y

yy在同一條重鏈上為止,最後分類討論跳x

xx還是跳y

yy,在合併的時候為了合併的正確性,我們把所有跳x

xx的結果合併後的總區間翻轉(實際上只交換了lsls

ls和r srs

rs),再與y

yy的答案合併。

由於本題合併操作較多,建議寫乙個merge函式。

還有,應該不需要**了吧。(作者畫圖畫到自閉)

#include

#define max 100005

#define inf (ll)1e16

#define ll long long

#define int ll

#define lc(x) (x<<1)

#define rc(x) (x<<1|1)

#define mid ((l+r)>>1)

using

namespace std;

int n, q, cnt, tot;

int head[max]

, next[max*2]

, vet[max*2]

;int sz[max]

, top[max]

, f[max]

, son[max]

, d[max]

, id[max]

, rk[max]

;ll val[max]

;void

add(

int x,

int y)

void

dfs1

(int x,

int fa)

}void

dfs2

(int x,

int t)

}/****segment tree***/

struct node

} s[max*4]

;ll tag[max*4]

;inline node merge

(node a, node b)

inline

void

push_up

(int x)

inline

void

mark

(int p,

int l,

int r, ll k)

inline

void

push_down

(int p,

int l,

int r)

void

build

(int p,

int l,

int r)

build(lc

(p), l, mid)

;build(rc

(p), mid+

1, r)

;push_up

(p);

}void

update

(int p,

int l,

int r,

int ul,

int ur, ll k)

push_down

(p, l, r);if

(mid >= ul)

update(lc

(p), l, mid, ul, ur, k);if

(mid < ur)

update(rc

(p), mid+

1, r, ul, ur, k)

;push_up

(p);

}node query

(int p,

int l,

int r,

int ul,

int ur)

push_down

(p, l, r);if

(mid < ul)

else

if(mid >= ur)

else

}/******end******/

void

modify

(int x,

int y, ll k)

update(1

,1,n, id[top[x]

], id[x]

, k)

; x = f[top[x]];

}if(id[x]

> id[y]

)swap

(x, y)

;update(1

,1,n, id[x]

, id[y]

, k);}

ll get_mx

(int x,

int y)

else}if

(id[x]

< id[y]

)else

swap

(qx.ls, qx.rs)

; res =

merge

(qx, qy)

;return res.mx;

}signed

main()

int x, y;

for(

int i =

1; i < n; i++

)dfs1(1

,0);

dfs2(1

,1);

build(1

,1,n);

cin >> q;

int t;

ll k;

for(

int i =

1; i <= q; i++

)else

}return0;

}

LCA的樹鏈剖分實現

這篇本來是要在 樹鏈剖分小節 中寫的,但是我感覺這只是樹鏈剖分的乙個衍生物,所以另開了一篇,如果對樹鏈剖分部分還不是太了解,請看上面的鏈結。計算樹中兩個節點的最近公共祖先,我們一般有爬山法,tarjan離線演算法,或者是將lca轉換成rmq來解,這裡講一講一種新的求lca的演算法,它是基於樹鏈剖分的...

狐假虎威的樹鏈剖分

運算元據結構 線段樹 結束語 最近在做運輸計畫這道題時,發現要用數鏈剖分,於是就打算學學這個玩意兒。其實之前一直以為這個東西是個很複雜的東西,可能 看起來都很長。但是,學了之後,我才發現,這個東西很好懂,而且 之所以很長,也有乙個原因就是它需要使用乙個強大的資料結構 線段樹。線段樹的 其實並不算少,...

樹鏈剖分的學習理解

前言 本文僅為本人學習樹鏈剖分的理解和總結,有誤之處請大佬指點迷津。也有與其他部落格不同或矛盾之處。樹鏈剖分 顧名思義,將樹結構,剖分成鏈狀結構,然後將一條條的鏈拼接成線性結構,然後就可以通過線段樹 樹狀陣列等維護了。說白了就是在樹上,有些值不好維護,通過樹鏈剖分轉化成乙個序列,而序列就好維護了。樹...