對於一棵樹,僅僅保留有用的點,重新構建一棵樹
有用的點一般指的是詢問點和它們的lca
一般題目的詢問巨大,並且有 ∑詢問
點數
\sum 詢問點數
∑詢問點
數思路:
直接樹形dp會tle,於是建出虛樹後在虛樹上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...