樹鏈剖分習題 2(提高)

2021-10-07 16:07:15 字數 4265 閱讀 1070

題意:給定一棵樹每條邊都帶有權值,給定 m 個詢問查詢 u 和 v 的路徑上權值小於等於 w 的邊的個數

思路:先拆點將邊權變為點權,可以離線來做。將點權小於當前詢問權值的點,更新到線段樹上,然後在查詢路徑上出現過的點的數量。(大於詢問權值的點,還沒更新上去)

#include .h>

#define ll long

long

#define ls (rt<<1)

#define rs (rt<<1|

1)using namespace std;

const

int maxn=

2e5+

10,mod=

1e9+7;

int head[maxn]

,cnt;

struct edge

edges[maxn<<1]

;void

add(

int u,

int v)

struct opt

}e[maxn]

,opt[maxn]

;int n,m;

int num[maxn]

,depth[maxn]

,fa[maxn]

,son[maxn]

;int start[maxn]

,top[maxn]

,times;

int st[maxn<<2]

;void

dfs1

(int u)

}void

dfs2

(int u,

int x)

}void

update

(int rt,

int p,

int l,

int r)

int mid=

(l+r)

>>1;

if(p<=mid)

update

(ls,p,l,mid);if

(p>mid)

update

(rs,p,mid+

1,r)

; st[rt]

=st[ls]

+st[rs];}

intquery

(int rt,

int l,

int r,

int l,

int r)

intqpath

(int u,

int v)

if(depth[u]

>depth[v]

)swap

(u,v)

; ans+=

query(1

,start[u]

,start[v],1

,n);

return ans;

}int ans[maxn]

;int

main()

;}for(

int i=

1;i<=m;

++i);}

sort

(e+1

,e+1

+n-1);

sort

(opt+

1,opt+

1+m)

;int nn=n-1;

n=tot;

dfs1(1

);dfs2(1

,1);

int p=1;

for(

int i=

1;i<=m;

++i)

for(

int i=

1;i<=m;

++i)

printf

("%d\n"

,ans[i]);

return0;

}

也可以用樹剖+主席樹來做,邊權下推成點權。將按dfs序訪問到的權值,更新到主席樹上,對於每次詢問 u,v,可以得到很多重鏈: top

[u

]top[u]

top[u]

和 uu

u,它們對應的時間序為 sta

rt[t

op[u

]]

start[top[u]]

start[

top[

u]] 和 sta

rt[u

]start[u]

start[

u],也就對應主席樹兩個版本sta

rt[t

op[u

]]−1

start[top[u]]-1

start[

top[

u]]−

1 和 sta

rt[u

]start[u]

start[

u],在這兩個版本之間查詢找 小於等於 k 的數即可。

#include .h>

using namespace std;

const

int maxn=

1e5+10;

int head[maxn]

,cnt;

struct edge

edges[maxn<<1]

;void

add(

int u,

int v,

int w)

struct opt

opt[maxn]

;int n,m;

vector<

int>

allw;

int total,wt[maxn]

,ww[maxn]

;int depth[maxn]

,num[maxn]

,fa[maxn]

,son[maxn]

;int start[maxn]

,top[maxn]

,times;

int st[maxn*40]

,root[maxn]

,ls[maxn*40]

,rs[maxn*40]

,no;

void

dfs1

(int u)

}void

dfs2

(int u,

int x)

}int

build

(int l,

int r)

intupdate

(int pre,

int l,

int r,

int p)

intquery

(int pre,

int now,

int l,

int r,

int l,

int r)

intqpath

(int u,

int v,

int p)

if(depth[u]

>depth[v]

)swap

(u,v)

; ans+=

query

(root[start[u]

],root[start[v]],

1,p,

1,total)

;return ans;

}int

main()

for(

int i=

1;i<=m;

++i)

; allw.

push_back

(w);

}sort

(allw.

begin()

,allw.

end())

; allw.

resize

(unique

(allw.

begin()

,allw.

end())

-allw.

begin()

);dfs1(1

);dfs2(1

,1);

total=allw.

size()

; root[0]

=build(1

,total)

;for

(int i=

1;i<=n;

++i)

for(

int i=

1;i<=m;

++i)

return0;

}/*3 21 3 2

1 2 7

2 3 4

2 3 7

*/

樹鏈剖分 樹鏈剖分講解

好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 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...

SPOJ QTREE2 樹鏈剖分

題意 有一棵n個節點的樹 1 n 10000 n 1條邊,邊的編號為1 n 1,每條邊有乙個權值,要求模擬兩種操作 1 dist a b 求 點a到點b之間的距離 2 kth a b k 求從a出發到b遇到的第k個節點的編號 qtree系列的第二題。求dist就不用說啦,主要是求第k個。方法一 我是...

SPOJ QTREE2 樹鏈剖分

題意 有一棵n個節點的樹 1 n 10000 n 1條邊,邊的編號為1 n 1,每條邊有乙個權值,要求模擬兩種操作 1 dist a b 求 點a到點b之間的距離 2 kth a b k 求從a出發到b遇到的第k個節點的編號 qtree系列的第二題。求dist就不用說啦,主要是求第k個。方法一 我是...