题面
temporaryDO 是一个很菜的 OIer。在 4 月,他在省队选拔赛的考场上见到了《林克卡特树》一题,其中 k = 0 k = 0 k=0 的部分分是求树 T T T 上的最长链。可怜的 temporaryDO 并不会做这道题,他在考场上抓猫耳挠猫腮都想不出一点思路。
这时,善良的板板出现在了空中,他的身上发出璀璨却柔和的光芒,荡漾在考场上。“题目并不难。” 板板说。那充满磁性的声音,让 temporaryDO 全身充满了力量。
他决定:写一个枚举点对求 LCA 算距离的 k = 0 k = 0 k=0 的 O ( n 2 log n ) O(n^2 \log n) O(n2logn) 的部分分程序!于是, temporaryDO 选择以 1 1 1 为根,建立了求 LCA 的树链剖分结构,然后写了二重 for 循环枚举点对。
然而,菜菜的 temporaryDO 不小心开小了数组,于是数组越界到了一片神秘的内存区域。但恰好的是,那片内存区域存储的区域恰好是另一棵树
T
′
T'
T′ 。这样一来,程序并没有 RE ,但他求
x
x
x 和
y
y
y 的距离的时候,计算的是
d
e
p
t
h
(
x
)
+
d
e
p
t
h
(
y
)
−
(
d
e
p
t
h
(
L
C
A
(
x
,
y
)
)
+
d
e
p
t
h
′
(
L
C
A
′
(
x
,
y
)
)
)
\mathrm{depth}(x) + \mathrm{depth}(y) - ({\mathrm{depth}(\mathrm{LCA}(x,y))}+{\mathrm{depth'}(\mathrm{LCA'}(x,y))})
depth(x)+depth(y)−(depth(LCA(x,y))+depth′(LCA′(x,y)))
最后程序会输出每一对点对 i , j i, j i,j( i ≤ j i \le j i≤j) 的如上定义的“距离” 的最大值。temporaryDO 的程序在评测时光荣地爆零了。但他并不服气,他决定花好几天把自己的程序跑出来。请你根据 T T T 和 T ′ T' T′ 帮帮可怜的 temporaryDO 求出他程序的输出。
输入格式
第一行包含一个整数 n n n ,表示树上的节点个数。
第 2 2 2 到第 n n n 行,每行三个整数 x , y , v x , y , v x,y,v ,表示 T T T 中存在一条从 x x x 到 y y y 的边,其长度为 v v v。
第 n + 1 n + 1 n+1 到第 2 n − 1 2n-1 2n−1 行 ,每行三个整数 x , y , v x , y , v x,y,v ,表示 T ′ T' T′ 中存在一条从 x x x 到 y y y 的边,其长度为 v v v。
输出格式
输出一行一个整数,表示 temporaryDO 的程序的输出。
样例
输入
6
1 2 2
1 3 0
2 4 1
2 5 -7
3 6 0
1 2 -1
2 3 -1
2 5 3
2 6 -2
3 4 8
输出
5
数据范围
对于所有数据, 1 ≤ n ≤ 366666 1\le n \le 366666 1≤n≤366666, ∣ v ∣ ≤ 2017011328 |v| \le 2017011328 ∣v∣≤2017011328 。 详细数据范围见下表,表格中的“无” 表示无特殊限制。
测试点编号 | n ≤ n \le n≤ | v v v | T T T 是一条链 | T ′ T' T′ 是一条链 |
---|---|---|---|---|
1 1 1 | 36 36 36 | = 1 =1 =1 | 否 | 否 |
2 2 2 | 366 366 366 | = 1 =1 =1 | 否 | 否 |
3 3 3 | 1388 1388 1388 | > 0 >0 >0 | 否 | 否 |
4 4 4 | 1999 1999 1999 | > 0 >0 >0 | 否 | 否 |
5 5 5 | 2666 2666 2666 | > 0 >0 >0 | 否 | 否 |
6 6 6 | 5666 5666 5666 | 无 | 否 | 否 |
7 7 7 | 8666 8666 8666 | 无 | 否 | 否 |
8 8 8 | 11111 11111 11111 | 无 | 否 | 否 |
9 9 9 | 12345 12345 12345 | 无 | 否 | 否 |
10 10 10 | 366666 366666 366666 | > 0 >0 >0 | 是 | 是 |
11 11 11 | 366666 366666 366666 | 无 | 是 | 是 |
12 ∼ 13 12\sim 13 12∼13 | 366666 366666 366666 | > 0 >0 >0 | 是 | 否 |
14 14 14 | 366666 366666 366666 | 无 | 是 | 否 |
15 ∼ 16 15\sim 16 15∼16 | 366666 366666 366666 | > 0 >0 >0 | 否 | 是 |
17 17 17 | 366666 366666 366666 | 无 | 否 | 是 |
18 ∼ 20 18\sim 20 18∼20 | 366666 366666 366666 | 无 | 否 | 否 |
d e p t h ( p ) \mathrm{depth}(p) depth(p) 和 d e p t h ′ ( p ) \mathrm{depth'}(p) depth′(p) 分别表示树 T T T, T ′ T' T′ 中点 1 1 1 到点 p p p 的距离,这里规定,距离指的是经过的边的边权总和,其中 d e p t h ( 1 ) = 0 \mathrm{depth}(1) = 0 depth(1)=0。
L C A ( x , y ) \mathrm{LCA}(x, y) LCA(x,y) 和 L C A ′ ( x , y ) \mathrm{LCA'}(x, y) LCA′(x,y) 分别表示树 T T T, T ′ T' T′ 中点 x x x 与点 y y y 的最近公共祖先,即在从 x x x 到 y y y 的最短路径上的距离根经过边数最少的点。
题解
我们令
d
i
s
(
x
,
y
)
\mathrm{dis}(x,y)
dis(x,y) 为
T
T
T 中
x
,
y
x,y
x,y 两点的距离(路径上的边权和),那么答案等价于
d
e
p
t
h
(
x
)
+
d
e
p
t
h
(
y
)
+
d
i
s
(
L
C
A
(
x
,
y
)
)
−
d
e
p
t
h
′
(
L
C
A
′
(
x
,
y
)
)
2
\cfrac{\mathrm{depth}(x) + \mathrm{depth}(y) + {\mathrm{dis}(\mathrm{LCA}(x,y))}-{\mathrm{depth'}(\mathrm{LCA'}(x,y))}}{2}
2depth(x)+depth(y)+dis(LCA(x,y))−depth′(LCA′(x,y))
那么我们可以对 T T T 进行边分治,记录每个点到分治中心的距离,转化成点权,左部和右部其中一边加上分治中心的边权,然后在 T ′ T' T′ 上建立该连通子树的虚树,求每个点作为 L C A LCA LCA 时两个不同部后代点权和的最大值。
建立虚树的复杂度或常数要尽量小,若建立虚树的复杂度为 T ( n ) T(n) T(n) ,则算法时间复杂度为 O ( T ( n ) log n ) O(T(n)\log n) O(T(n)logn) 。
注: x = y x=y x=y 时的贡献是 d e p t h ( x ) − d e p t h ′ ( x ) {\rm depth}(x)-{\rm depth'}(x) depth(x)−depth′(x)
CODE
一个函数实现三度化,虚树复杂度 O ( n log n ) O(n\log n) O(nlogn) ,重链剖分常数。
#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 736670
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB long double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
#define getchar() xchar()
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
int n,m,s,o,k;
int hd[MAXN],nx[MAXN<<3],v[MAXN<<3],cne;
LL w[MAXN<<3];
int hd2[MAXN],hd3[MAXN];
LL de[MAXN];
int d[MAXN],fa[MAXN],sz[MAXN],sn[MAXN],tp[MAXN],dfn[MAXN],tim;
bool cmp(int a,int b) {return dfn[a] < dfn[b];}
LL dept[MAXN];
bool f[MAXN],tg[MAXN];
LL dp[MAXN],elen;
int siz[MAXN],SIZ,el,er,ls,rs;
int op[MAXN];
int ar[MAXN],cna;
LL ans = -1e18;
LL nm1[MAXN],nm2[MAXN];
void ins1(int x,int y,LL z) {
nx[++ cne] = hd[x]; v[cne] = y; hd[x] = cne; w[cne] = z;
}
void ins2(int x,int y,LL z) {
nx[++ cne] = hd2[x]; v[cne] = y; hd2[x] = cne; w[cne] = z;
}
void ins(int cne,int x) {nx[cne] = hd[x]; hd[x] = cne;}
void ins3(int x,int y,LL z) {
nx[++ cne] = hd3[x]; v[cne] = y; hd3[x] = cne; w[cne] = z;
}
void dfs0(int x,int ff) {
d[x] = d[fa[x] = ff] + 1;
sz[x] = 1; sn[x] = 0;
for(int i = hd2[x];i;i = nx[i]) {
if(v[i] != ff) {
de[v[i]] = de[x] + w[i];
dfs0(v[i],x);
sz[x] += sz[v[i]];
if(sz[v[i]] > sz[sn[x]]) sn[x] = v[i];
}
}return ;
}
void dfs0_(int x,int ff) {
if(sn[ff] == x) tp[x] = tp[ff];
else tp[x] = x;
dfn[x] = ++ tim;
if(sn[x]) dfs0_(sn[x],x);
for(int i = hd2[x];i;i = nx[i]) {
if(v[i] != ff && v[i] != sn[x]) {
dfs0_(v[i],x);
}
}return ;
}
int lca(int a,int b) {
while(tp[a] != tp[b]) {
if(d[tp[a]] > d[tp[b]]) a = fa[tp[a]];
else b = fa[tp[b]];
}return d[a] < d[b] ? a:b;
}
void dfs00(int x,int ff) {
int ct = 0; tg[x] = 1;
for(int i = hd[x];i;i = nx[i]) {
if(!tg[v[i]]) ct ++;
}
if(ct > 3) {
int l = ++ m,r = ++ m,op = 0;
for(int i = hd[x],j = nx[i];i;i = j,j = nx[i],op ^= 1) {
if(tg[v[i]]) {op ^= 1; continue;}
if(op) ins(i,r);
else ins(i,l);
}
hd[x] = 0;
ins1(x,l,0); ins1(x,r,0);
}
else {
int hed = hd[x]; hd[x] = 0;
for(int i = hed,j = nx[i];i;i = j,j = nx[i]) {
if(tg[v[i]]) {continue;}
ins(i,x);
}
}
for(int i = hd[x];i;i = nx[i]) {
if(!tg[v[i]]) {
dept[v[i]] = dept[x] + w[i];
dfs00(v[i],x);
ins1(v[i],x,w[i]);
}
}
return ;
}
void dfs(int x,int ff) {
siz[x] = 1;
for(int i = hd[x];i;i = nx[i]) {
if(v[i] != ff && !f[v[i]]) {
dfs(v[i],x);
siz[x] += siz[v[i]];
if(min(SIZ-siz[v[i]],siz[v[i]]) >= min(ls,rs)) {
ls = SIZ-siz[v[i]]; rs = siz[v[i]];
el = x; er = v[i]; elen = w[i];
}
}
}return ;
}
void cont(int x,int ff,int o,LL wi) {
if(x <= n) op[x] = o,ar[++ cna] = x,dp[x] = wi + dept[x];
for(int i = hd[x];i;i = nx[i]) {
if(v[i] != ff && !f[v[i]]) cont(v[i],x,o,wi + w[i]);
}return ;
}
int build(int *a,int le) {
sort(a + 1,a + 1 + le,cmp);
static int st[MAXN],tp;
st[tp = 1] = a[1]; hd3[a[1]] = 0;
for(int i = 2;i <= le;i ++) {
int p = 0,lc = lca(a[i],st[tp]);
while(tp > 0 && d[lc] <= d[st[tp]]) {
if(p) ins3(st[tp],p,de[p] - de[st[tp]]);
p = st[tp --];
}st[++ tp] = lc;
if(p && p != lc) hd3[lc] = 0,ins3(lc,p,de[p] - de[lc]);
if(a[i] != lc) hd3[a[i]] = 0,st[++ tp] = a[i];
}
int p = 0;
while(tp > 0) {
if(p) ins3(st[tp],p,de[p] - de[st[tp]]);
p = st[tp --];
}return p;
}
void calc(int x) {
nm1[x] = -1e18; nm2[x] = -1e18;
if(op[x] == 1) nm1[x] = dp[x];
if(op[x] == 2) nm2[x] = dp[x];
for(int i = hd3[x];i;i = nx[i]) {
calc(v[i]);
ans = max(ans,nm1[x] + nm2[v[i]] - de[x]*2);
ans = max(ans,nm2[x] + nm1[v[i]] - de[x]*2);
nm1[x] = max(nm1[x],nm1[v[i]]);
nm2[x] = max(nm2[x],nm2[v[i]]);
}op[x] = 0; hd3[x] = 0;
return ;
}
void solve(int x,int si) {
if(si == 1) {
if(x <= n) ans = max(ans,dept[x]*2-de[x]*2);
return ;
}
SIZ = si;
ls = rs = 0;
dfs(x,0);
cna = 0;
cont(el,er,1,elen); cont(er,el,2,0);
int ce = cne;
int rt = build(ar,cna),lsi = ls,rsi = rs,lp = el,rp = er;
calc(rt);
cne = ce;
f[rp] = 1; solve(lp,lsi); f[rp] = 0;
f[lp] = 1; solve(rp,rsi); f[lp] = 0;
return ;
}
int main() {
n = read(); m = n;
for(int i = 1;i < n;i ++) {
s = read();o = read();
LL k = read();
ins1(s,o,k); ins1(o,s,k);
}
for(int i = 1;i < n;i ++) {
s = read();o = read();
LL k = read();
ins2(s,o,k); ins2(o,s,k);
}
dfs0(1,0);
dfs0_(1,0);
dfs00(1,0);
solve(1,m);
AIput(ans/2,'\n');
return 0;
}