話說mored經過不懈努力,終於背完了迴圈整數,也終於完成了他的蛋糕大餐。
但是不幸的是,mored得到了詛咒,受到詛咒的原因至今無人知曉。
mored在發覺自己得到詛咒之後,決定去尋找聞名遐邇的術士cd幫忙。
話說cd最近在搞oi,遇到了一道有趣的題目:
給定兩棵樹,則總共有n*m種方案把這兩棵樹通過加一條邊連成一棵樹,那這n*m棵樹的直徑大小之和是多少呢?
cd為了考驗mored是否值得自己費心力為他除去詛咒,於是要他程式設計回答這個問題,但是這mored早就被詛咒搞暈了頭腦,就只好請你幫助他了。
第一行兩個正整數n,m,分別表示兩棵樹的大小。
接下來n-1行,每行兩個正整數ai,bi,表示第一棵樹上的邊。
接下來m-1行,每行兩個正整數ci,di,表示第二棵樹上的邊。
一行乙個整數,表示答案。
4 31 22 3
2 41 3
2 3
53【資料範圍】
對於20%的資料滿足n<=300,m<=300
對於50%的資料滿足n,m<=3000
對於100%的資料滿足n<=10^5,m<=10^5,1<=ai,bi<=n,1<=ci,di<=m
【提示】
樹的直徑指的是樹上的最長簡單路徑。
solution
預處理a[i]表示樹a上以i開頭的最長鏈
同理b[i]表示樹b上以i開頭的最長鏈
f[i]為i向下的最長鏈,dp[i]為向上的最長鏈
那麼f[i]用樹形dp可以求出
考慮求dp[i]
g[i]為i向下的不與最長鏈的共有子節點的最長的鏈
舉例:son[i]為i向下最長鏈的子節點 g[i] 就是除了son[k]外所有子節點向下的最長鏈+1
表述不清。。。
可以自己想想怎麼求a,b
令max表示a樹和b樹的直徑的max
排序統計即可
#include#include#include#include#include#include#define maxn 100005
using namespace std;
int n,m,tot,head[maxn],f[maxn],g[maxn],dp[maxn],t1,t2;
long long a[maxn],b[maxn],sum[maxn],ans,ma;
struct nodee[maxn*2];
void lj(int t1,int t2)
void dfs1(int k,int fa)
else max2=max(max2,f[e[i].v]);}}
if(max==-1e9)f[k]=0,g[k]=-1e9;
else
//cout<>n>>m;
for(int i=1;i=1;i--)
cout<
return 0;
}
樹的合併 connect
話說mored經過不懈努力,終於背完了迴圈整數,也終於完成了他的蛋糕大餐。但是不幸的是,mored得到了詛咒,受到詛咒的原因至今無人知曉。mored在發覺自己得到詛咒之後,決定去尋找聞名遐邇的術士cd幫忙。話說cd最近在搞oi,遇到了一道有趣的題目 給定兩棵樹,則總共有n m種方案把這兩棵樹通過加一...
樹的合併 connect
話說mored經過不懈努力,終於背完了迴圈整數,也終於完成了他的蛋糕大餐。但是不幸的是,mored得到了詛咒,受到詛咒的原因至今無人知曉。mored在發覺自己得到詛咒之後,決定去尋找聞名遐邇的術士cd幫忙。話說cd最近在搞oi,遇到了一道有趣的題目 給定兩棵樹,則總共有n m種方案把這兩棵樹通過加一...
線段樹合併
做永無鄉的時候,以為是主席樹合併,後來感覺不對勁,唔。x和y是兩顆樹的根。這個演算法是從歸併演算法那引申的。實際運作的時候,考慮到了線段樹的本質 線段樹有效節點就是葉子節點。好像是句廢話。其實不是,這句話啟發我們並不需要合併一整棵樹,我們只需要處理好葉子節點,考慮把y樹合併到x上,那麼把y樹的葉子節...