離線操作 樹鏈剖分 LNOI2014 LCA

2021-09-12 17:59:41 字數 3695 閱讀 7833

【題目描述】

給出乙個n個節點的有根樹(編號為0到n-1,根節點為0)。乙個點的深度定義為這個節點到根的距離+1。

設dep[i]表示點i的深度,lca(i,j)表示i與j的最近公共祖先。

有q次詢問,每次詢問給出l r z,求∑

l<=i

<=r

dep[

lca(

i,z)

]\sum_dep[lca(i,z)]

l<=i

<=r

∑​de

p[lc

a(i,

z)]。

(即,求在[l,r]區間內的每個節點i與z的最近公共祖先的深度之和)

【輸入】

第一行2個整數n q。

接下來n-1行,分別表示點1到點n-1的父節點編號。

接下來q行,每行3個整數l r z。

【輸出】

輸出q行,每行表示乙個詢問的答案。每個答案對201314取模輸出

【樣例輸入】

5 2001

11 4 3

1 4 2

【】樣例輸出】85

【提示】

共5組資料,n與q的規模分別為10000,20000,30000,40000,50000。

這道題的做法不得不說很巧妙。

我們可以構造乙個等價問題。如果我們把u到根節點經過的每乙個點的權值加一,那麼我們可以發現v到根節點經過的點的權值之和就是dep[lca(u,v)]。這是乙個十分優美的性質,因為它不僅滿足區間加法,甚至滿足區間減法。因此我們對於每乙個詢問l,r,z,我們可以利用字首和思想得到ans[l,r,z]=ans[1,r,z]-ans[1,l-1,z]。那麼現在的問題就只剩下如何得到z到根節點的權值和以及修改節點到1的權值。顯然,修改和維護路徑資訊,我們就使用樹鏈剖分+線段樹了。

**:

#include

#include

#include

#include

#include

#include

#define re register

#define ll long long

#define lc (p<<1)

#define rc (p<<1|1)

#define len(p) (t[p].r-t[p].l+1)

using

namespace std;

long

long n,m,a,b,c;

struct nodee[

200001];

struct treet[

400001];

long

long f[

100001];

long

long nxp[

200001];

long

long cnt=

0,tot=0;

inline

void

add(

long

long u,

long

long v)

long

long son[

100001];

long

long siz[

100001];

long

long dep[

100001];

long

long fa[

100001];

long

long top[

100001];

long

long seg[

100001];

long

long rev[

100001];

void

dfs1

(long

long u,

long

long ff)

}void

dfs2

(long

long u)

for(

long

long re i=f[u]

;i;i=nxp[i])}

void

pushup

(long

long p)

void

pushnow

(long

long p,

long

long v)

void

pushdown

(long

long p)

}void

build

(long

long p,

long

long l,

long

long r)

struct queq[

100001];

vectorp[

50001];

void

change

(long

long p,

long

long ql,

long

long qr)

pushdown

(p);

long

long mid=

(l+r)

>>1;

if(ql<=mid)

change

(lc,ql,qr);if

(qr>mid)

change

(rc,ql,qr)

;pushup

(p);

}long

long sum=0;

void

ask(

long

long p,

long

long ql,

long

long qr)

pushdown

(p);

long

long mid=

(l+r)

>>1;

if(ql<=mid)

ask(lc,ql,qr);if

(qr>mid)

ask(rc,ql,qr);}

void

update

(long

long x)

change(1

,seg[1]

,seg[x]);

}void

query

(long

long x)

ask(

1,seg[1]

,seg[x]);

}int

main()

tot=top[1]

=dep[1]

=rev[1]

=seg[1]

=1;build(1

,1,n);

dfs1(1

,0);

dfs2(1

);for(

long

long re i=

1;i<=m;i++

)for

(long

long re i=

0;i<=n;i++)}

for(

long

long re i=

1;i<=m;i++

)printf

("%lld\n"

,(q[i]

.sum[1]

-q[i]

.sum[0]

)%201314);

}

樹鏈剖分 樹鏈剖分講解

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

LNOI2014 LCA 差分 樹剖

葉子最可愛啦qwq!每次詢問乙個區間和乙個點,求這個區間所有點和給定點的lca的深度和。深度和是吧。lca的深度和有乙個很優良的性質。你把乙個點到根的權值都 1,查另乙個點到根的權值就是這個深度。那問題轉化成了鏈加鏈求和。不過有q個詢問哦。怎麼辦呢?很明顯這個詢問應該被去掉。我們不乙個詢問乙個詢問查...

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

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