題目
邊分治+虛樹=雙倍的快樂
這個柿子裡有兩個\(lca\),我們考慮魔改一下前面的\(\operatorname\),為了方便邊分,我們考慮把\(\operatorname\)去掉變換為樹上距離
經過一番魔改,這個柿子變成了\(\frac(\operatorname)\)
至於第二棵樹上的\(\operatorname\),我們只能考慮到虛樹上去搞了
對於當前的分治邊\(w\),我們處理處分塊內所有點\(i\)到這條邊的距離\(p_i\),那麼\(\operatorname=p_x+p_y+w+depth_x+depth_y\)
同時我們把分治邊左右兩邊的點黑白染色,點權設為\(p_i+depth_i\),到第二顆樹上去建虛樹,對於虛樹上的每個點考慮其作為\(\operatorname\)時的貢獻,於是把問題轉化成了在乙個點的不同兒子裡找到一對異色點,使得點權最大,顯然直接虛樹上dp就好了
如果虛樹實現得不好,這個演算法就是\(\operatorname\)
如果使用st表求\(\operatorname\),並且在一開始就把所有點按照\(\operatorname\)排序,每次根據這個點染成的顏色分到兩個接下來的分治塊裡去,就能做到線性建虛樹,整個演算法的複雜度就能到\(\operatorname\)
記得特判\(x=y\)的情況
**
#include#define re register
#define ll long long
#define pt putchar(1)
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=366667;
const int m=maxn*4;
const ll inf=-1e15;
inline int read()
while(c>='0'&&c<='9') x=(x<<3ll)+(x<<1ll)+c-48,c=getchar();return r*x;
}std::vectorson[m];
std::vectorv[m];
struct ee[m<<1];
int head[m],sum[m],vis[m],dfn[maxn],b[maxn];
int s,mnow,rn,n,num,col[maxn],rt,mnow,tp[2],c[2][maxn];
ll g[maxn],dp[maxn][2],deep[maxn],tmp,ans;
inline int cmp(int a,int b)
void tree_dp(int x)
} inline void get_tree(int l,int r)
void del(int x)
}t;void dfs2(int x,int fa,int o,ll d)
}void solve(int x,int s,int l,int r)
int main()
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...
CTSC2018 暴力寫掛 邊分樹合併
ctsc2018 暴力寫掛 題面不錯 給定兩棵樹,兩點 距離 定義為 二者深度相加,減去兩棵樹上的lca的深度 深度指到根節點的距離 求最大的距離。解決多棵樹的問題就是降維了。經典的做法是邊分樹合併。邊分樹結構類似0 1 trie 就是把邊分樹對於每個點拆開路徑 合併兩棵邊分樹同時可以得到兩個邊分樹...
WC2018 通道 與 CTSC2018 暴力寫掛
兩個都給出點分治的做法,看起來邊分治不光跑的慢還沒什麼不可替代性?暴力寫掛 考慮那個式子有兩個不同樹上的 operatorname 不好處理,考慮怎麼換成乙個 由於 dis x,y deep x deep y 2deep operatorname x,y 於是用 dis 代換 dfrac dis x...