樹鏈剖分 四 旅行

2021-10-24 08:53:11 字數 3407 閱讀 9810

解題思路

樹鏈剖分+動態開點線段樹。可以通過樹鏈剖分將問題轉化成詢問序列上與起點相同宗教的權值總和及最大值,並且支援單點更新。這個問題可以用線段樹解決,但一般線段樹要開四倍空間,而且要維護不同宗教,所以空間肯定不夠。但是我們可以動態開點,樹上每個點最多對應logn個點,所以動態開點最多也就nlogn個點,空間就夠了,就是犧牲了常數的時間去開點,在這是可以接受的。

ac**

#include

#include

#include

#include

using

namespace std;

const

int maxn=

1e5+5;

const

int maxm=

2e7+5;

const

int inf=

0x3f3f3f3f

;struct node

edge[maxn<<1]

;//鏈式前向星

int head[maxn]

,num[maxn]

,root[maxn]

;struct node

tree[maxm]

;int cnt,n,q,len;

intget()

//快讀

void

add(

int x,

int y)

int fa[maxn]

;//x在樹中的父親

int dep[maxn]

;//x在樹中的深度

int size[maxn]

;//x的子樹結點數(子樹大小)

int son[maxn]

;//x的重兒子,即u->son[u]是重邊

int top[maxn]

;//x所在重路徑的頂部頂點(深度最小)

int seg[maxn]

;int rev[maxn]

;//線段樹中第x位置對應的樹中結點編號,rev[seg[x]]=x

int w[maxn]

;int zj[maxn]

;int ssum,mmax;

void

update

(int

&rt,

int l,

int r,

int val,

int pos)

//val是評級,os你要新增的點的fs序

void

remove

(int

&rt,

int l,

int r,

int pos)

int mid=

(l+r)

>>1;

if(mid>=pos)

remove

(tree[rt]

.l,l,mid,pos)

;else

remove

(tree[rt]

.r,mid+

1,r,pos)

; tree[rt]

.sum=tree[tree[rt]

.l].sum+tree[tree[rt]

.r].sum;

tree[rt]

.max=

max(tree[tree[rt]

.l].max,tree[tree[rt]

.r].max);}

intquerysum

(int rt,

int lb,

int rb,

int l,

int r)

intquerymax

(int rt,

int lb,

int rb,

int l,

int r)

void

dfs1

(int u,

int f)

//第一遍dfs,算出fa,dep,size,son

}void

dfs2

(int u,

int f)

//第二遍dfs,算出top,seg,rev

for(

int i=head[u]

;i;i=edge[i]

.next)

}void

asksum

(int x,

int y,

int zj)

//路徑詢問

ssum+

=querysum

(root[zj],1

,n,seg[fx]

,seg[x]);

//重路徑對應區間[seg[fx],seg[x]]

x=fa[fx]

; fx=top[x];}

if(dep[x]

>dep[y]

)swap

(x,y)

; ssum+

=querysum

(root[zj],1

,n,seg[x]

,seg[y]);

}void

askmax

(int x,

int y,

int zj)

mmax=

max(mmax,

querymax

(root[zj],1

,n,seg[fx]

,seg[x]))

;//重路徑對應區間[seg[fx],seg[x]]

x=fa[fx]

; fx=top[x];}

if(dep[x]

>dep[y]

)swap

(x,y)

; mmax=

max(mmax,

querymax

(root[zj],1

,n,seg[x]

,seg[y]))

;}intmain()

for(

int i=

1;i++i)

dfs1(1

,0);

seg[0]

=seg[1]

=top[1]

=rev[1]

=1;//根結點所在重路徑的頂部結點一定還是根結點

dfs2(1

,0);

for(

int i=

1;i<=n;

++i)

update

(root[zj[i]],

1,n,w[i]

,seg[i]);

char str[20]

;while

(q--

)else

}else

else}}

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 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...