20200722 專題 虛樹

2021-10-08 09:54:16 字數 4908 閱讀 6511

對於一棵樹,僅僅保留有用的點,重新構建一棵樹

有用的點一般指的是詢問點和它們的lca

一般題目的詢問巨大,並且有 ∑詢問

點數

\sum 詢問點數

∑詢問點

數思路:

直接樹形dptle,於是建出虛樹後在虛樹上dp

虛樹的構建:

將詢問點按dfn排序,然後用棧維護最外側的鏈

**:

#include

using

namespace std;

#define int long long

namespace io

inline

intin()

}// namespace io

using

namespace io;

const

int a =

5e5+5;

const

int inf =

1e18

;int n, m;

int head[a]

, tot_road;

struct road road[

2* a]

;inline

void

edge

(int x,

int y,

int w)

; head[x]

= tot_road;

}int dep[a]

, f[a]

, son[a]

, sz[a]

, top[a]

, pos[a]

, minn[a]

, tot;

int num, qur[a]

;inline

bool

cmp(

int x,

int y)

inline

void

dfs1

(int fa,

int x)

return;}

inline

void

dfs2

(int x)

for(

int y = head[x]

; y; y = road[y]

.nex)

return;}

inline

intlca

(int x,

int y)

return dep[x]

< dep[y]

? x : y;

}inline

void

prepare()

int cur[a]

;road net[

2* a]

;int st[a]

, sum;

inline

void

ljb(

int x,

int y,

int w =0)

; cur[x]

= tot_road;

}inline

void

build()

int k =

lca(qur[i]

, st[sum]);

if(k == st[sum]

)continue

;while

(sum && pos[k]

< pos[st[sum -1]

])if(st[sum]

!= k)

st[++sum]

= qur[i];}

for(

int i = sum; i >

1; i--

)ljb

(st[i -1]

, st[i]);

return;}

int dp[a]

;inline

voiddp(

int x)

dp[x]

= minn[x];if

(tmp) dp[x]

=min

(dp[x]

, tmp)

; cur[x]=0

;return;}

inline

void

clean()

signed

main()

prepare()

; m =in(

);while

(m--

)return0;

}

思路:

建出虛樹

在虛樹上dp出虛樹上每個點屬於的點(兩次dfs,先用兒子更新父親,再用父親更新兒子)

對於虛樹上的一條邊,對應樹上一條鏈

分情況討論

如果兩端點屬於同一點

如果兩端點不屬於同一點

對於情況一,這條鏈上所有點都屬於同一點

對於情況二,可以倍增出兩點的分界處,然後同情況一

注意細節

計算鏈上的點時包含子樹,不算端點,端點單獨容斥計算

**:

#include

using

namespace std;

namespace io

inline

intin()

}// namespace io

using

namespace io;

const

int a =

5e5+5;

const

int k =22;

const

int inf =

1e9;

int n;

struct road

int nex, to, w;};

int lg[a]

;namespace lca

int dep[a]

, sz[a]

, pos[a]

, tot;

int to[a]

[k];

inline

void

dfs(

int fa,

int x)

return;}

inline

intlca

(int x,

int y)

}// namespace lca

int q, m;

int qur[a]

, tw[a]

, is[a]

;inline

bool

cmp(

int x,

int y)

namespace vt

int st[a]

, top;

inline

void

build()

int k = lca::

lca(st[top]

, x);if

(k == st[top]

)while

(top >

1&& lca::pos[k]

< lca::pos[st[top -1]

])if(k != st[top]

) st[

++top]

= x;

}for

(int i = top; i >

1; i--

)edge

(st[i -1]

, st[i]);

return;}

int p[a]

, dis[a]

;inline

void

dfs1

(int x)

for(

int y = head[x]

; y; y = road[y]

.nex)

if(dis[x]

== dis[z]

+(lca::dep[z]

- lca::dep[x]

)&& p[z]

< p[x]

) p[x]

= p[z];}

return;}

inline

void

dfs2

(int x)

if(dis[z]

== dis[x]

+(lca::dep[z]

- lca::dep[x]

)&& p[x]

< p[z]

) p[z]

= p[x]

;dfs2

(z);

}return;}

int ans[a]

;inline

void

find

(int x)

else

else

}find

(z);

} head[x]=0

;return;}

inline

void

work()

}// namespace vt

signed

main()

lca::

dfs(0,

1); q =in(

);while

(q--

)sort

(qur +

1, qur +

1+ m, cmp)

; vt::

build()

; vt::

work()

;for

(int i =

1; i <= m; i++

)puts(""

);}return0;

}

樹套樹專題

對資料結構的不熟練 題目鏈結 嘗試一下樹狀陣列套主席樹的寫法。小細節沒有重視 為了方便起見,一般我們寫getrank x 求的都是 1 include2 const int maxn 50035 3 const int maxnode 5000035 4 const int inf 21474836...

專題講解 樹專題 遞迴思路處理樹

我們都以二叉樹作為乙個標準的例子分析樹的問題常用的方法。首先我們先來分析遞迴的方法。有乙個很好的二叉樹的三步走戰略,我覺著很值得學習。三步走 方法的三步分別為 可以看出,核心有兩個,乙個是拆解子問題,乙個是是否使用全域性變數。全域性變數的使用很靈活的,因為python是可以返回多個變數,因此只是乙個...

線段樹專題

最最基礎的線段樹,只更新葉子節點,然後把資訊用pushup int r 這個函式更新上來。hdu1166 敵兵布陣 線段樹 hdu 1166 敵兵布陣 單點更新區間求和 hdu1754 i hate it 線段樹 hdu 1754 i hate it 單點更新 區間求最值 hdu1394 minim...