題目鏈結
兩棵樹 , 求出下面式子的最大值。
d ep
[u]+
dep[
v]−d
ep[l
ca(u
,v)]
−dep
′[lc
a′(u
,v)]
dep[u]+dep[v]-dep[lca(u,v)]-dep'[lca'(u,v)]
dep[u]
+dep
[v]−
dep[
lca(
u,v)
]−de
p′[l
ca′(
u,v)
]邊分治。
與第一棵樹有關的資訊比較多,所以對第一棵樹邊分。
l ca
lcalc
a 在分治中不好處理 ,因為我們要換根還要快速合併路徑資訊,那麼把式子變個形:
d ep
[u]+
dep[
v]+d
is[u
][v]
2−de
p′[l
ca′(
u,v)
]\frac-dep'[lca'(u,v)]
2dep[u
]+de
p[v]
+dis
[u][
v]−
dep′
[lca
′(u,
v)]這個樣子的話在邊分的過程中就可以直接把 乙個點的深度與它到當前分治邊的某個端點的距離作為點權了。這樣我們只需要快速求出在第二棵樹中選出兩個不在同一集合中的點使得他們的權值減去他們的 lca 在第二棵樹中的深度的最大值。
直接虛樹 + 樹形dp 就可以了。
其實這個題目還是比較板的,沒有太大的思維難度。
#include
using
namespace std;
#define set(a,b) memset(a,b,sizeof(a))
template
<
class
t>
inline
void
init
(t&x)
struct edge
;const
int n=
4e5+10;
typedef
long
long ll;
typedef vector<
int> ary;
const ll inf=
1e16
;int n,tn;
ll *val,upd;
int s[2]
[n];
ll ans=0;
namespace tree2
;head[x]
=cnt;
}void
dfs(
int u,
int fa)
return;}
inline
intck
(int u,
int v)
inline
intlca
(int u,
int v)
inline ll query
(int u,
int v)
void
build()
namespace vitual_tree
ll f[2]
[n];
inline
void
insert
(int u)
void
dfs(
int u)
head[u]=0
;bel[u]=-
1;}void
work()
}using vitual_tree::work;
}namespace tree1
;head[x]
=cnt++;}
inline
void
add_edge
(int u,
int v,
int z)
ary son[maxn]
;void
dfs(
int u,
int fa)
return;}
int cedge;
inline
void
rebuild()
else}}
return;}
inline
void
build()
dfs(1,
0);rebuild()
;return;}
int mx,tot;
void
find
(int u,
int fa)
return;}
void
dfs(
int u,
int fa,
int*s,ll dep)
return;}
inline
void
divide
(int u,
int siz)
inline
void
solve()
}int
main()
CTSC2018 暴力寫掛
題目 邊分治 虛樹 雙倍的快樂 這個柿子裡有兩個 lca 我們考慮魔改一下前面的 operatorname 為了方便邊分,我們考慮把 operatorname 去掉變換為樹上距離 經過一番魔改,這個柿子變成了 frac operatorname 至於第二棵樹上的 operatorname 我們只能考...
CTSC2018 暴力寫掛
題目鏈結 ctsc2018 暴力寫掛 做法 dep x dep y dep lca x,y dep lca x,y frac dep x dep y 2dep lca x,y dep x dep y 2dep lca x,y frac dis x,y dep x dep y 2dep lca x,y...
bzoj 5341 Ctsc2018 暴力寫掛
邊分治 邊分樹合併 這個題很多做法都是啟發式合併的複雜度的,都有點卡 以前有個套路叫做線段樹合併優化啟發式合併,消掉乙個 log 這個題思路類似,建出邊分樹,通過一些操作把它變成線段樹,就可以線段樹合併了 首先邊分樹的相關定理 如果一棵包含 n 個結點的樹中每個點的度均不大於 d 那麼存在一條邊,使...