题意
给一个n个节点的树,每条边都有权值,求出两条不相交链边权和的乘积最大
数据范围:
n
≤
4
⋅
1
0
5
∣
c
i
∣
≤
1
0
9
n\le 4\cdot 10^5\quad \left | c_i \right|\le10^9
n≤4⋅105∣ci∣≤109
ps:51nod支持int128,边权可能为负
只有ans需要__int128,其他的都可以开long long
先用dfs求出每个节点,由v节点向下的链的最大权值和
d
o
w
n
[
v
]
down[v]
down[v],和可经过v节点的最大链权值和
b
e
s
t
[
v
]
best[v]
best[v](可以是当前子树内的一条链,也可以是从一个子树的最长链连到另一个子树的最长链之和)
然后用bfs遍历每个节点u和其所有的儿子v“截断”这条边,求两棵树内的最长链之积。
现在就有以u为根节点的一棵树,和以v为根节点的一棵树,我们记outside为以u为根节点的树中的最长链。
u
p
[
u
]
up[u]
up[u]为u向上可获得的最长链
p
r
e
d
o
w
n
[
]
predown[]
predown[]为u的儿子
d
o
w
n
[
]
down[]
down[]的最大前缀
p
p
r
e
d
o
w
n
[
]
ppredown[]
ppredown[]为u的儿子
d
o
w
n
[
]
down[]
down[]的次大前缀
p
r
e
b
e
s
t
[
]
prebest[]
prebest[]为u的儿子
b
e
s
t
[
]
best[]
best[]的最大前缀
s
u
f
d
o
w
n
[
]
sufdown[]
sufdown[]为u的儿子
d
o
w
n
[
]
down[]
down[]的最大后缀
s
s
u
f
d
o
w
n
[
]
ssufdown[]
ssufdown[]为u的儿子
d
o
w
n
[
]
down[]
down[]的次大后缀
s
u
f
b
e
s
t
[
]
sufbest[]
sufbest[]为u的儿子
b
e
s
t
[
]
best[]
best[]的最大后缀
通过这些数组,可以
O
(
1
)
O(1)
O(1)求出outside对于任意u的儿子的所有组合,当枚举到儿子v时
outside = up[u] + max(predown[i - 1], sufdown[i + 1]);
outside = max(outside, predown[i - 1] + ppredown[i - 1]);
outside = max(outside, sufdown[i + 1] + ssufdown[i + 1]);
outside = max(outside, predown[i - 1] + sufdown[i + 1]);
outside = max(outside, max(prebest[i - 1], sufbest[i + 1]));
更新
up[v] = w + max(up[u], max(predown[i - 1], sufdown[i + 1]));
que.push(make_pair(v, u));
运用bfs和儿子的前缀后缀处理算法
复杂度
O
(
n
)
O(n)
O(n)
#include <bits/stdc++.h>
#define int long long
#define ll __int128
using namespace std;
const int MAX_N = 400010;
inline void read(int &x){
x = 0; int f = 1; char ch = getchar();
while (!(ch >= '0' && ch <= '9')){if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
int n, total;
int head[MAX_N];
ll best[MAX_N], down[MAX_N];
ll prebest[MAX_N], sufbest[MAX_N], predown[MAX_N], ppredown[MAX_N];
ll sufdown[MAX_N], ssufdown[MAX_N], up[MAX_N];
struct Edge{
int to, next, w;
}edge[MAX_N * 2];
inline void AddEdge(int from, int to, int w){
edge[total].to = to, edge[total].next = head[from], edge[total].w = w;
head[from] = total++;
}
void dfs(int u, int p){
ll Max = 0, MMax = 0;
for (int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if (v == p) continue;
dfs(v, u);
int t = down[v] + edge[i].w;
if (t > Max){
MMax = Max;
Max = t;
}else if (t > MMax){
MMax = t;
}
best[u] = max(best[u], best[v]);
}
down[u] = Max;
best[u] = max(best[u], Max + MMax);
}
ll ans = -1;
void solve()
{
queue<pair<int, int> > que;
que.push(make_pair(1, 0));
while (!que.empty()){
pair<int, int> cur = que.front();
int u = cur.first, p = cur.second;
que.pop();
vector<pair<int, int> > child;
child.push_back(make_pair(0, 0));
for (int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if (v != p) child.push_back(make_pair(v, edge[i].w));
}
int size = child.size();
prebest[0] = predown[0] = ppredown[0] = 0;
for (int i = 1; i < size; ++i){
int v = child[i].first, w = child[i].second;
prebest[i] = max(prebest[i - 1], best[v]);
predown[i] = predown[i - 1], ppredown[i] = ppredown[i - 1];
if (down[v] + w > predown[i]){
ppredown[i] = predown[i];
predown[i] = down[v] + w;
}else if (down[v] + w > ppredown[i]){
ppredown[i] = down[v] + w;
}
}
sufbest[size] = sufdown[size] = ssufdown[size] = 0;
for (int i = size - 1; i >= 1; --i){
int v = child[i].first, w = child[i].second;
sufbest[i] = max(sufbest[i + 1], best[v]);
sufdown[i] = sufdown[i + 1], ssufdown[i] = ssufdown[i + 1];
if (down[v] + w > sufdown[i]){
ssufdown[i] = sufdown[i];
sufdown[i] = down[v] + w;
} else if (down[v] + w > ssufdown[i]){
ssufdown[i] = down[v] + w;
}
}
for (int i = 1; i < size; ++i){
int v = child[i].first;
ll outside = up[u] + max(predown[i - 1], sufdown[i + 1]);
outside = max(outside, predown[i - 1] + ppredown[i - 1]);
outside = max(outside, sufdown[i + 1] + ssufdown[i + 1]);
outside = max(outside, predown[i - 1] + sufdown[i + 1]);
outside = max(outside, max(prebest[i - 1], sufbest[i + 1]));
if (outside * best[v] > ans) ans = outside * best[v];
}
for (int i = 1; i < size; ++i){
int v = child[i].first, w = child[i].second;
up[v] = w + max(up[u], max(predown[i - 1], sufdown[i + 1]));
que.push(make_pair(v, u));
}
}
}
inline void write(ll x){if (x >= 10) write(x / 10); putchar((x % 10) + 48);}
signed main(){
int n;
read(n);
memset(head, -1, sizeof(head));
total = 0;
for (int i = 1; i < n; ++i){
int u, v, w;
read(u), read(v), read(w);
AddEdge(u, v, w);
AddEdge(v, u, w);
}
dfs(1, 0);
solve();
for (int i = 0; i < total; i++) edge[i].w = -edge[i].w;
memset(best, 0, sizeof(best));
memset(down, 0, sizeof(down));
memset(up, 0, sizeof(up));
dfs(1, 0);
solve();
write(ans);
return 0;
}