bzoj 3626 LCA(樹鏈剖分)

2021-08-14 19:21:26 字數 2004 閱讀 9600

傳送門biu~

考慮求lca

(x,y

) 的深度,可以把

x 到根路徑上的所有節點權值加一,再查詢

y到根路徑上的所有節點的權值和即為lc

a(x,

y)的深度。

將詢問離線,把詢問σr

i=ld

eplc

a(i,

z)拆成兩個詢問:σr

i=1d

eplc

a(i,

z)減去σl

−1i=

1dep

lca(

i,z)

。從1 到n列舉

i ,每次把

i到根路徑上的所有節點權值加一,如果在位置

i 有乙個關於

z的詢問,就查詢

z 到根路徑上的所有節點的權值和。

#include

using

namespace

std;

const

long

long mod=201314ll;

int n,q;

struct datatree[200005];

struct ques

}p[100005];int cnt;

inline

bool cmp_r(ques a,ques b)

void dfs1(int x,int father)

}void dfs2(int x,int tp)

}void buildtree(int num,int l,int r)

void pushdown(int x)

(tree[x<<1].sum+=(tree[x<<1].r-tree[x<<1].l+1)*tree[x].mark)%=mod;

(tree[x<<1|1].sum+=(tree[x<<1|1].r-tree[x<<1|1].l+1)*tree[x].mark)%=mod;

(tree[x<<1].mark+=tree[x].mark)%=mod;

(tree[x<<1|1].mark+=tree[x].mark)%=mod;

tree[x].mark=0;

}void modify(int num,int l,int r)

int mid=tree[num].l+tree[num].r>>1;

if(mid>=r) modify(num<<1,l,r);

else

if(mid1|1,l,r);

else modify(num<<1,l,mid),modify(num<<1|1,mid+1,r);

tree[num].sum=(tree[num<<1].sum+tree[num<<1|1].sum)%mod;

}inline

void modify(int x)

modify(1,pos[top[x]],pos[x]);

}long

long query(int num,int l,int r)

inline

long

long query(int x)

(re+=query(1,pos[top[x]],pos[x]))%=mod;

return re;

}int main()

dfs1(1,0);dfs2(1,1);

buildtree(1,1,n);

for(int i=1;i<=q;++i)

sort(p+1,p+cnt+1,cmp_r);

int fir=1;

while(p[fir].r==0) ++fir;

for(int i=1;i<=n;++i)

}sort(p+1,p+cnt+1,cmp_id);

for(int i=1;i<=cnt;i+=2) printf("%lld\n",(p[i].sum-p[i+1].sum+mod)%mod);

return

0;}

LCA 樹鏈剖分

剛打完lca板子,寫個東西記下 dfs第一遍求出 結點i的深度,以i為根的子樹大小,結點i的父親,並求出重鏈 dfs第二遍求出 結點i所在重鏈的鏈頂 如果在重鏈上 開始lca,兩個點往上找,深度大的點就往上跳,這個點如果在重鏈上,就跳到所在重鏈的鏈頂的父親處,在輕鏈上,就直接跳到自己父親上 洛谷lc...

樹鏈剖分求LCA

這裡先推薦兩道練習的裸題 首先是求點 codevs4605 lca 就是求兩個點的公共祖先,每次詢問xor上上乙個詢問的答案。先是兩遍dfs dfs1 把dep siz son求出來 dfs2 求出top和w siz v 表示以v為根的子樹的節點數 dep v 表示v的深度 根深度為1 top v ...

樹鏈剖分求lca

題目描述 給一棵有根樹,以及一些詢問,每次詢問樹上的2 個節點a b,求它們的最近公共祖先.輸入第一行乙個整數n.接下來n 個數,第i 個數fi 表示i 的父親是fi.若fi 0,則i 為樹根.接下來乙個整數m.接下來m 行,每行2 個整數a b,詢問節點 a xor lastans bxor la...