【題目描述】
給出乙個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 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查詢 標記下傳 標記永久化 閱讀全文 樹鏈剖分用...