樹論 兩棵樹

2022-09-10 00:21:42 字數 2616 閱讀 2043

wc2018 t1 簡化版 by oblack.

有兩棵有 n​ 個節點的樹,分別為 a,b,樹上每條邊都有乙個權值 v_i​

令 disa(x,y) 和 disb(x,y) 分別表示 x 節點與 y 節點在樹 a,b 上的距離

請你找出乙個點對 (x,y) 使得 disa(x,y)+disb(x,y) 取得最大值,注意 x!=y

輸入格式

第一行,乙個整數 n

接下來 n-1 行,每行三個整數 x_i,y_i,v_i ,表示 a 上的一條邊

接下來 n-1 行,每行三個整數 x_i,y_i,v_i ,表示 b 上的一條邊

輸出格式

輸出乙個整數 ans ,表示最大值

樣例輸入

54 5 6

4 1 2

5 2 1

4 3 0

4 1 9

4 2 0

1 5 0

5 3 7

樣例輸出

23提示

對於 30% 的資料, n<=2000,v_i<=10^6

對於所有資料, n<=10^5, v_i<=10^12

本題為  wc2018 t1 (nkoj  5004) 簡化版我們將dis1(x,y)+dis2(x,y)變一下形 --> dep1[x] + dep1[y] - 2*dep1[lca1(x,y)] + dep2[x] + dep2[y] - 2*dep2[lca2(x,y)]

我們發現對於任何x,他的dep1[x]和dep2[x]在式子中總是成對出現的。那麼我們將他們合併在一起考慮-->方法是將第二棵樹中的x,每個對應在其下連一條dep1[x]的邊,並設定新節點為x'。同時我們在第一棵樹中列舉lca,那麼問題就變成了--->對於第一棵樹的lca,對於他的分別兩個子樹合併的時候的兩個點集,分別對應在第二棵樹中的兩個離散的點集,在其中找一條最長的路徑。也就是比如對於x的son1對應一些點集,son2對應一些點集,(因為在這兩個點集中各選乙個保證他們在第一棵樹樹上的lca一定為x)然後兩個中各自挑選乙個的最長路徑。

其實對於這樣兩個離散點集中,分別各自對應著兩個直徑。容易證明。對於兩個離散點集,他們之間的最長路徑的端點一定是分別在他們的直徑4個點上。同時,也可以證明,對於兩個離散點集他們合併之後的那個點集的直徑的端點,也一定是兩個離散點集的四個端點之二。

這樣我們只需要變換一下第二顆樹,然後在第一棵樹上dfs合併子樹,在第二顆樹上查詢最長路徑更新答案(lca次數比較多,考慮o(1)lca),就可以了。。

/*

在第一棵樹上列舉lca,由於式子

disa(x,y) + disb(x,y) == dep1x + dep1y -2*lca1 + dep2x + dep2y - 2*lca2

可以在第二棵樹上外掛程式乙個節點,那麼就是對於第二棵樹上的乙個點集內的求點集了

然後直接直徑合併就可以了

*/#include#include#include#include#include#define pr pair#define fi first

#define se second

using namespace std;

typedef long long ll;

const int maxn = 1000005;

const int maxm = 2000005;

ll len1[maxm];

int la1[maxn],nt1[maxm],en1[maxm],owo1;

void addedge1(int a,int b,ll c)

ll len2[maxm];

int la2[maxn],nt2[maxm],en2[maxm],owo2;

void addedge2(int a,int b,ll c)

ll dep1[maxn],dep2[maxn];

int n;

int st[23][maxn*2],lac[maxn],oula;

char buf[1<<20],*p1,*p2;

#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)

//#define gc getchar()

inline ll r()

void dfs1(int x,int ba)

}int logg[maxn*2];

int s;

void dfs2(int x,int ba)

lac[x] = oula;

}ll ans = -1e18;

int getlca(int x,int y)

tmp = getcd(a.fi,b.fi);

if(tmp>ccd)

tmp = getcd(a.fi,b.se);

if(tmp>ccd)

tmp = getcd(a.se,b.fi);

if(tmp>ccd)

tmp = getcd(a.se,b.se);

if(tmp>ccd)

return now;

}pr dfs3(int x,int ba)

return zj;

}main()

}dfs3(1,0);

printf("%lld",ans);

}

兩棵樹的命運

農夫在地里種下了兩粒種子,很快它們變成了兩棵同樣大小的樹苗。第一棵樹開始就決心長成乙個參天大樹,所以它拼命地從地下吸收養料,儲備起來,滋潤每一枝樹幹,盤算著怎樣向上生長,完善自身。由於這個原因,在最初的幾年,它並沒有結果實,這讓農夫很惱火。相反另一棵樹,也拼命地從地下吸取養料,打算早點開花結果,它做...

判斷兩棵樹是否相等

思路 兩棵樹相等當且僅當roota data rootb data,且a和b的左右子樹相等或左右子樹互換相等 用遞迴的方式進行求解 1 if 兩棵樹都為空 返回true 2 if 兩棵樹中一棵為空,另一棵不為空 返回false 3 if 資料相等 else if 第一棵樹的左子樹與第二棵樹的右子樹相...

WPF的兩棵樹與繫結

原文 wpf的兩棵樹與繫結 public class visualpanel frameworkelement public visualpanel protected override int visualchildrencount protected override visual getvis...