8 4 樹鏈剖分

2022-08-19 13:45:14 字數 3555 閱讀 4852

詳解:

樹鏈剖分的本質是序

以盡量走重鏈為序,使一棵樹的結點盡量集中地分解成較少的鏈,而鏈作為連續的資料結構是易於維護的

剖分的過程有兩遍dfs :

dfs1:找出重結點 ,確立各個點的深度 ,這個過程可以確定:sz[i] ,dep[i] ,fa[i] ,son[i]

void dfs1( int u ,int

f )}

void dfs2( int u ,int

t )}

剖分後就可以利用線段樹,樹狀陣列等資料結構對分解後的鏈進行維護,給定兩個節點x,y,進行它們之間的更新和查詢操作,這個過程是:

1.如果x,y在一條重鏈上( top[x]==top[y] ),則可以直接利用資料結構對x到y這一段連續的鏈進行直接操作

2.如果x,y不在一條重鏈上( top[x] != top[y] ),找出較深的結點(dep[fx]>dep[fy])x,先將x到fx這一小段進行操作,再令x向其重鏈之上的父節點轉移

重複這一過程,直到完成x到y之間完整路徑的操作

這一過程也是尋找x,y lca 的過程

int lca( int x ,int

y )

return dep[x] < dep[y] ?x : y ;

}

int c_query( int x ,int

y )

if( x==y )return

ans;

if( dfn[x] >dfn[y] )swap( x ,y );

if(dfn[x] != dfn[y])ans += query( 1

,dfn[son[x]] ,dfn[y] );

return

ans ;

}

線段樹: 網上關於樹鏈剖分的**線段樹大多都是以結構體形式寫的:

struct

treetree[n

<<2];

難道這樣更快?不懂(可能這個問題我永遠也不會搞懂

模板題:hdu 3966 aragorn's

story

區間修改,單點查詢

這個我線段樹沒用結構體寫也過了

#include#define fi first

#define se second

#define rep( i ,x ,y ) for( int i= x; i<= y ;i++ )

#define reb( i ,y ,x ) for( int i= y; i>= x ;i-- )

#define mem( a ,x ) memset( a ,x ,sizeof(a))

#define lson pos<<1 ,l ,m

#define rson pos<<1|1 ,m+1 ,r

using

namespace

std;

typedef

long

long

ll;typedef

long

double

ld;typedef pair

pii;

typedef pair

pll;

typedef pair

psi;

const

int inf = 0x3f3f3f3f

;const

int n = 50005

;const

int m = 1000005

;struct

edgeedge[n

<<2

];int

sz[n] ,top[n] ,son[n] ,dep[n];

intfa[n] ,dfn[n] ,rnk[n];

int m ,n ,q ,tot = 0 ,cnt = 0

,k;int

head[n] ;

ll val[n

<<2] ,tree[n<<4] ,lazy[n<<4

];//

線段樹部分

void build( int pos ,int l ,int

r )

int m = (l+r)>>1

; build ( rson );

build ( lson );

tree[pos] = tree[pos<<1]+tree[pos<<1|1

];

return;}

void push_down( int

pos )

void updata( int pos ,int l, int r ,int l ,int r ,int

k )

int m = ( l+r )>>1

;

if( l <=m )updata( lson ,l ,r ,k);

if( r >m )updata( rson ,l ,r ,k);

tree[pos] = tree[pos>>1] + tree[pos>>1|1

];

return;}

ll query(

int pos ,int l ,int r ,int l ,int

r )//

樹鏈剖分部分 --dfs1 ,dfs2 ,query ,updata

void dfs1( int u ,int rt ,int

d ) }

return;}

void dfs2( int u ,int

t ) dfs2( son[u] ,t );

for( int i = head[u]; i ; i =edge[i].next )

}ll query_path(

int x ,int

y)

else

fx = top[x] ,fy =top[y];

}if(x !=y )

else

} else ans += query( 1 ,1

,n,dfn[x] ,dfn[y] );

return

ans;

}void updata_path( int x ,int y ,int

z )

else

fx = top[x] ,fy =top[y];

}if( x!=y )

else updata( 1 ,1

, n, dfn[x] ,dfn[y] ,z);

}int

main( )

dfs1(

1 ,1 ,0

); dfs2(

1 ,1

); build(

1, 1

,n );

char

op;

while ( q--)

if( op == 'q'

)

if( op == 'd'

) }

}return0;

}

樹鏈剖分 樹鏈剖分講解

好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...

演算法入門 樹鏈剖分 輕重鏈剖分

目錄 3.0 求 lca 4.0 利用資料結構維護資訊 5.0 例題 參考資料 資料結構入門 線段樹 發表於 2019 11 28 20 39 dfkuaid 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查詢 標記下傳 標記永久化 閱讀全文 樹鏈剖分用...

樹鏈剖分 樹剖換根

這是一道模板題。給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...