DTOJ 5021 最近公共祖先

2021-10-10 07:14:38 字數 3977 閱讀 7698

作為此次 noip 模擬的最後一道題,宮水三葉決定把題意說得簡單一點。

給一棵大小為 n

nn 的以 rtrt

rt為根的樹。

有 m

mm 組詢問,每次詢問 l,r

,x

l,r,x

l,r,

x,你要回答有多少 l≤a

rl \le a < b \le r

l≤ar,滿足 a,b

a,ba,

b 的最近公共祖先為 x

xx 。

第一行三個整數 n,m

,r

tn,m,rt

n,m,rt

。接下來 n−1

n-1n−

1 行,每行兩個整數 xi,

yi

x_i,y_i

xi​,yi

​ ,表示一條邊。

接下來 m

mm 行,每行三個整數 li,

ri,x

il_i,r_i,x_i

li​,ri

​,xi

​ ,表示一組詢問。

輸出共 m

mm 行,第 i

ii 行表示第 i

ii 個詢問的答案。

樣例輸入 1

10 10 7

4 210 4

3 26 10

9 27 3

1 48 2

5 38 10 10

2 6 2

3 6 2

4 6 4

3 10 2

8 8 10

3 10 4

2 3 2

2 6 4

1 7 10

樣例輸出 1
020

1702

010

樣例資料 2

見下發檔案。

本題採用**測試。

對於所有測試點,滿足 1≤n

,m≤2

×105

,1≤r

t≤

n1\le n,m \le 2\times 10^5,1\le rt \le n

1≤n,m≤

2×10

5,1≤

rt≤n

。子任務編號

n ,m

n,mn,

m分值1 11≤

200\le 200

≤200

5 552

22≤

2000

\le 2000

≤200020

2020

3 33≤

5×10

4\le 5\times 10^4

≤5×104

35

3535

4 44≤

2×10

5\le 2\times 10^5

≤2×105

40

4040

提示本題時間限制為2s,請選手注意io用時。

題解:首先,多組詢問區間,容易想到 莫隊。

但 o (n

n)

o(n\sqrt n)

o(nn​)

的時間複雜度只能支援 o(1

)o(1)

o(1)

修改。但查詢可以 o(n

)o(\sqrt n)

o(n​

),這啟發我們樹鏈剖分。

但普通的重兒子太過平均,不如把子樹大小前 o(n

)o(\sqrt n)

o(n​

) 個全部劃為重兒子。

這樣就能維護了。

#include

#define n 400005

typedef

long

long ll;

using

namespace std;

inline

intread()

while

(s>=

'0'&&s<=

'9')

return x*f;

}int tot,head[n]

,ver[n<<1]

,nex[n<<1]

;int dfn[n]

,dfs_num,sz[n]

,fa[n]

,st[n]

,ed[n]

;inline

void

add(

int x,

int y)

void

dfs(

int x,

int las)

ed[x]

=dfs_num;

}int sq,i_he[n]

,sqm;

priority_queueint,

int>

> q;

vector<

int> he[n]

;ll sum[n]

,del[n]

;struct nodeque[n]

;bool

c***

(node a,node b)

bool

cmp(node a,node b)

int nex_li[n]

,n;ll li_del[n]

,li_sz[n]

;void

fin_li

(int x,

int las)

}void

work

(int x,

int val)

ll sum_ou[n]

,sum_in[n]

;struct nodeop[n<<1]

;bool

cmp2

(node a,node b)

vector p_sz[n]

;inline

void

test()

inline ll ge

(int x)

inline

voidch(

int x)

intmain()

dfs(rt,0)

;// cout(int i=

1;i<=n;

++i)

}while

(!q.

empty()

)}for(

int i=

1;i<=m;

++i)

fin_li

(rt,0)

;int l=

0,r=0;

sort

(que+

1,que+

1+m,cmp)

;for

(int i=

1;i<=m;

++i)

for(

int i=

1;i<=m;

++i)

sort

(op+

1,op+1+

2*m,cmp2)

;//cout(int i=

1,j=

1;i<=n;

++i)

else p_sz[id]

[k]+

=now,del[id]

+=p_sz[id]

[k]*p_sz[id]

[k];

//sum[id]+=val*now;

}++j;}}

//cout(que+

1,que+

1+m,c***)

;for

(int i=

1;i<=m;

++i)

return0;

}/*5 1 1

1 21 3

1 41 5

1 2 1

*/

最近公共祖先 python 最近公共祖先

lca演算法樸素演算法 也就是我們所說的暴力演算法,大致的思路是從樹根開始,往下迭代,如果當前結點比兩個結點都小,那麼說明要從樹的右子樹中找 相反則從左子樹中查詢 直到找到乙個結點在當前結點的左邊,乙個在右邊,說明當前結點為最近公共祖先,如果乙個結點是另外乙個結點的祖先,那麼返回前面結點的父親結點即...

最近公共祖先 LCA 最近公共祖先

直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...

最近公共祖先 最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...