CTSC2018 暴力寫掛

2022-05-20 07:18:30 字數 2952 閱讀 2139

題目鏈結

「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)))

\]考慮對第一棵樹邊分治。設當前分治重心為 $ u, v $ ,選擇 $ u $ 側節點 $ x $ ,選擇 $ v $ 側節點 $ y $ ,則令 $ x $ 為一類節點,貢獻為 $ e1(x) = dep(x) + dis(v, x) $ ;令 $ y $ 為二類節點,貢獻為 $ e2(y) = dep(y) + dis(v, y) $ 。列舉第二顆樹的 $ lca $ ,設 $ x, y $ 在第二顆樹中的 $ lca $ 為 $ lca $ ,則對答案的貢獻為 $ \frac(e1(x) + e2(y) - 2dep(lca)) $ 。由於需要正確的時間複雜度,所以需要對第二顆樹建虛樹進行 $ dp $ 。

不優秀的實現會導致時間複雜度為 $ o(n \log^2 n) $ ,由於每次建虛樹的時間複雜度應為 $ o(k) $ ,所以需要用 $ rmq $ 實現 $ o(1) $ 的 $ lca $ ;另外每次建虛樹需要將點排序,將排序放在分治之前,然後按照分治將數列分成兩段,每次建虛樹直接呼叫陣列(或者先分治下去再歸併排序然後建虛樹)。更改後時間複雜度為 $ o(n \log n) $ 。

注意 $ x $ 可以與 $ y $ 相同,而邊分治未考慮這一點,所以還要考慮 $ x = y $ 的情況。

#include #define rep(i, a, b) for(int i = (a); i <= (b); i++)

#define per(i, a, b) for(int i = (a); i >= (b); i--)

#define pb push_back

#define mp make_pair

#define fst first

#define snd second

using namespace std;

typedef long long ll;

typedef pairpil;

const ll inf = 1e17;

const int n = 800010;

int n, m; ll ans = -inf, w[n], fw[n];

vectore1[n], e2[n]; vectore[n]; int ar[n], len;

int dep[n], dfn[n], idx, a[n], st[20][n], lg[n]; ll dep[n];

int cnt = 1, to[n + n], nxt[n + n], hed[n]; ll val[n + n]; bool used[n + n];

int size, rte, mn, sz[n], tot;

ll value[n], f1[n], f2[n]; int flag[n], sta[n], top;

templatevoid gi(t &x)

inline void addedge(int x, int y, ll z)

inline bool cmp(const int &x, const int &y)

void getdfn(int u, int ff)

inline int lca(int x, int y)

int build(int l, int r)

void rebuild(int u, int ff)

void getrt(int u, int ff, int ed)

void find(int u, int ff, int opt, ll d)

void dfs(int u)

e[u].clear(), flag[u] = 0;

}void solve(vectorp)

for(; top > 1 && dep[sta[top - 1]] >= dep[lca]; --top) e[sta[top - 1]].pb(sta[top]);

if(lca != sta[top]) e[lca].pb(sta[top]), sta[top] = lca;

sta[++top] = v;

} for(; top > 1; --top) e[sta[top - 1]].pb(sta[top]); dfs(1);

}void solve(int u, vectorp)

int main()

rep(i, 2, n)

getdfn(1, 0); rep(i, 1, idx) st[0][i] = a[i];

lg[0] = -1; rep(i, 1, idx) lg[i] = lg[i >> 1] + 1;

for(int j = 1; (1 << j) <= idx; j++)

for(int i = 1; i <= idx - (1 << j) + 1; i++)

st[j][i] = dep[st[j - 1][i]] <= dep[st[j - 1][i + (1 << j - 1)]] ? st[j - 1][i] : st[j - 1][i + (1 << j - 1)];

rebuild(1, 0);

vectorp; rep(i, 1, n) p.pb(i); sort(p.begin(), p.end(), cmp);

size = m, mn = m + 1, getrt(1, 0, -1), solve(rte, p), ans /= 2;

rep(i, 1, n) ans = max(ans, w[i] - dep[i]);

printf("%lld\n", ans);

return 0;

}

CTSC2018 暴力寫掛

題目 邊分治 虛樹 雙倍的快樂 這個柿子裡有兩個 lca 我們考慮魔改一下前面的 operatorname 為了方便邊分,我們考慮把 operatorname 去掉變換為樹上距離 經過一番魔改,這個柿子變成了 frac operatorname 至於第二棵樹上的 operatorname 我們只能考...

CTSC2018 暴力寫掛 邊分樹合併

ctsc2018 暴力寫掛 題面不錯 給定兩棵樹,兩點 距離 定義為 二者深度相加,減去兩棵樹上的lca的深度 深度指到根節點的距離 求最大的距離。解決多棵樹的問題就是降維了。經典的做法是邊分樹合併。邊分樹結構類似0 1 trie 就是把邊分樹對於每個點拆開路徑 合併兩棵邊分樹同時可以得到兩個邊分樹...

WC2018 通道 與 CTSC2018 暴力寫掛

兩個都給出點分治的做法,看起來邊分治不光跑的慢還沒什麼不可替代性?暴力寫掛 考慮那個式子有兩個不同樹上的 operatorname 不好處理,考慮怎麼換成乙個 由於 dis x,y deep x deep y 2deep operatorname x,y 於是用 dis 代換 dfrac dis x...