「WC2018」通道
「WC2018」通道
解题思路:
问题要最大化三棵树上的路径和,码码码就完事了。
第一棵树上边分,对于每一个边分中心 \(mid\),钦点边左边的联通块为黑色,右边联通块为白色,令
\[f1(x)=\begin{cases} dis1(x,mid) & color(x)=black \\ dis1(x,mid) +weight(mid) & color(x) = white \\ 0 & otherwise\end{cases}
\]
对于这两个联通块的点建第二棵树上的虚树 \(T2\) 令
\[f2(x)= \begin{cases} 0 & color(x) = none \\ dep2(x) & otherwise\end{cases}
\]
那么遍历 \(T2\) 第 \(k\) 个节点时要计算的贡献就是
\[\max\{f1(x)+f1(y)+f2(x)+f2(y)-dis3(x,u)\} -2dep2(k)
\\ [color(x)=black,color = white,x,y\in subtree(k)]
\]
那么把 \(f1(x)+f2(x)\) 看做点权,维护在第三棵树上异色点对端点点权加上边权的最值,经典的直径合并套路,为了保证异色点,需要维护同色点对的直径。
复杂度视情况 \(\mathcal O(n\log n)\) 或者 \(\mathcal O(n\log^2n)\) 。
code
/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf ((ll)(1e18))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define int ll
#define fi first
#define se second
const int N = 300005;
int dis1[N], col[N], n, ANS;
namespace tree3{
vector<pair<int, int> > g[N];
int f[N][21], Log[N], ddep[N], dep[N], dfn[N], tot;
inline void addedge(int x, int y, int z){
g[x].push_back(make_pair(y, z));
g[y].push_back(make_pair(x, z));
}
inline int chkmin(int x, int y){
return ddep[x] < ddep[y] ? x : y;
}
inline void dfs(int u, int fa){
dfn[u] = ++tot, f[tot][0] = u;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i].fi;
if(v == fa) continue;
ddep[v] = ddep[u] + 1;
dep[v] = dep[u] + g[u][i].se;
dfs(v, u), f[++tot][0] = u;
}
}
inline int lca(int u, int v){
int x = dfn[u], y = dfn[v];
if(x > y) swap(x, y);
int g = Log[y-x+1];
return chkmin(f[x][g], f[y-(1<<g)+1][g]);
}
inline int dis3(int x, int y){
return dep[x] + dep[y] - 2 * dep[lca(x, y)];
}
inline void realmain(){
dfs(1, 0);
for(int i = 2; i <= tot; i++) Log[i] = Log[i>>1] + 1;
for(int j = 1; j <= 20; j++)
for(int i = 1; i + (1 << j) - 1 <= tot; i++)
f[i][j] = chkmin(f[i][j-1], f[i+(1<<(j-1))][j-1]);
}
}
namespace tree2{
vector<int> B, e[N];
vector<pair<int, int> > g[N];
int f[N][21], ff[N], ddep[N], Log[N], dep[N], dfn[N], st[N], top, tot;
inline void addedge(int x, int y, int z){
g[x].push_back(make_pair(y, z));
g[y].push_back(make_pair(x, z));
}
inline int chkmin(int x, int y){
return ddep[x] < ddep[y] ? x : y;
}
inline void dfs(int u, int fa){
dfn[u] = ++tot, f[tot][0] = u;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i].fi;
if(v == fa) continue;
dep[v] = dep[u] + g[u][i].se;
ddep[v] = ddep[u] + 1;
dfs(v, u), f[++tot][0] = u;
}
}
inline int lca(int u, int v){
int x = dfn[u], y = dfn[v];
if(x > y) swap(x, y);
int g = Log[y-x+1];
return chkmin(f[x][g], f[y-(1<<g)+1][g]);
}
inline void realmain(){
dfs(1, 0);
for(int i = 2; i <= tot; i++) Log[i] = Log[i>>1] + 1;
for(int j = 1; j <= 20; j++)
for(int i = 1; i + (1 << j) - 1 <= tot; i++)
f[i][j] = chkmin(f[i][j-1], f[i+(1<<(j-1))][j-1]);
}
inline bool cmp(int x, int y){
return dfn[x] < dfn[y];
}
inline int calc(int x, int y){
if(!x || !y) return -1;
return dep[x] + dep[y] + tree3::dis3(x, y) + dis1[x] + dis1[y];
}
inline pair<int, int> getbest(pair<int, int> A, pair<int, int> B){
pair<int, int> C = make_pair(A.fi, B.se);
pair<int, int> D = make_pair(A.fi, B.fi);
pair<int, int> E = make_pair(A.se, B.fi);
pair<int, int> F = make_pair(A.se, B.se);
if(calc(B.fi, B.se) > calc(A.fi, A.se)) A = B;
if(calc(C.fi, C.se) > calc(A.fi, A.se)) A = C;
if(calc(D.fi, D.se) > calc(A.fi, A.se)) A = D;
if(calc(E.fi, E.se) > calc(A.fi, A.se)) A = E;
if(calc(F.fi, F.se) > calc(A.fi, A.se)) A = F;
return A;
}
struct node{
pair<int, int> A, B;
inline void reset(){
A.fi = A.se = B.fi = B.se = 0;
}
friend node operator + (node left, node right){
node res;
res.A = getbest(left.A, right.A);
res.B = getbest(left.B, right.B);
return res;
}
friend int operator * (node left, node right){
return max(calc(left.A.fi, right.B.fi),
max(calc(left.A.fi, right.B.se),
max(calc(left.A.se, right.B.fi),
max(calc(left.A.se, right.B.se),
max(calc(left.B.fi, right.A.fi),
max(calc(left.B.fi, right.A.se),
max(calc(left.B.se, right.A.fi),
calc(left.B.se, right.A.se))))))));
}
} s[N];
inline void append(int x, int y){
ff[x] = y, st[++top] = x, B.push_back(x);
}
inline void make_tree(vector<int> &A){
top = 0, B.clear();
for(int i = 0; i < (int) A.size(); i++){
int u = A[i];
if(!top) append(u, 0);
else{
int x = lca(u, st[top]);
for(; top > 1 && ddep[st[top]] > ddep[x]; top--)
if(ddep[st[top-1]] < ddep[x]) ff[st[top]] = x;
if(st[top] != x) append(x, st[top]);
append(u, x);
}
}
for(int i = 0; i < (int) B.size(); i++)
if(B[i] > 1) e[ff[B[i]]].push_back(B[i]);
}
inline void dfs_for_ans(int u){
s[u].reset();
if(col[u] == 1) s[u].A = make_pair(u, u);
if(col[u] == 2) s[u].B = make_pair(u, u);
for(int i = 0; i < (int) e[u].size(); i++){
int v = e[u][i];
dfs_for_ans(v);
ANS = max(ANS, s[v] * s[u] - 2 * dep[u]);
s[u] = s[v] + s[u];
}
}
inline void solve(vector<int> &A){
if((int) A.size() <= 1) return;
sort(A.begin(), A.end(), cmp);
if(A[0] != 1){
reverse(A.begin(), A.end());
A.push_back(1);
reverse(A.begin(), A.end());
}
make_tree(A), dfs_for_ans(1);
for(int i = 0; i < (int) B.size(); i++)
ff[B[i]] = 0, e[B[i]].clear();
}
}
namespace tree1{
vector<int> qwq;
vector<pair<int, int> > g[N];
pair<int, int> RT;
int lst[N], vis[N], dep[N], sz[N], allsize, mnsize, cnt;
inline void addedge(int x, int y, int z){
g[x].push_back(make_pair(y, z));
g[y].push_back(make_pair(x, z));
}
inline void append(int x, int y, int z){
addedge(lst[x], ++cnt, 0);
addedge(lst[x] = cnt, y, z);
}
inline void build(int u, int fa){
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i].fi;
if(v == fa || v > n) continue;
append(u, v, g[u][i].se), build(v, u);
}
}
inline void dfs_pre(int u, int fa){
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i].fi;
if(v == fa) continue;
dep[v] = dep[u] + g[u][i].se, dfs_pre(v, u);
}
}
inline void getsize(int u, int fa){
int now = 0; sz[u] = 1;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i].fi;
if(v == fa || vis[v]) continue;
getsize(v, u), sz[u] += sz[v];
if(sz[v] > now) now = sz[v];
}
now = max(now, allsize - sz[u]);
if(now < mnsize && fa)
mnsize = now, RT = make_pair(u, fa);
}
inline pair<int, int> find_next_edge(int x, int y){
allsize = y, mnsize = inf;
getsize(x, 0); return RT;
}
inline void dfs_for_getpoint(int u, int fa, int d){
if(u <= n) qwq.push_back(u), dis1[u] = d;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i].fi;
if(v == fa || vis[v]) continue;
dfs_for_getpoint(v, u, d + g[u][i].se);
}
}
inline vector<int> getpoint(int x){
qwq.clear();
dfs_for_getpoint(x, 0, 0);
return qwq;
}
inline void divide(pair<int, int> now){
int x = now.fi, y = now.se;
vis[x] = vis[y] = 1;
vector<int> Ax = getpoint(x);
vector<int> Ay = getpoint(y);
vector<int> A;
for(int i = 0; i < (int) Ax.size(); i++){
dis1[Ax[i]] += abs(dep[x] - dep[y]);
col[Ax[i]] = 1, A.push_back(Ax[i]);
}
for(int i = 0; i < (int) Ay.size(); i++)
col[Ay[i]] = 2, A.push_back(Ay[i]);
tree2::solve(A);
for(int i = 0; i < (int) A.size(); i++)
col[A[i]] = dis1[A[i]] = 0;
int allx = sz[x], ally = allsize - sz[x];
if(allx > 1) vis[x] = 0, divide(find_next_edge(x, allx)), vis[x] = 1;
if(ally > 1) vis[y] = 0, divide(find_next_edge(y, ally)), vis[y] = 1;
}
inline void realmain(){
cnt = n;
for(int i = 1; i <= n; i++) lst[i] = i;
build(1, 0);
for(int i = 1; i <= n; i++){
vector<pair<int, int> > A;
for(int j = 0; j < (int) g[i].size(); j++)
if(g[i][j].fi > n) A.push_back(g[i][j]);
g[i] = A;
}
dfs_pre(1, 0);
if(n > 1) divide(find_next_edge(1, cnt));
}
}
signed main(){
read(n);
for(int i = 1, x, y, z; i < n; i++){
read(x), read(y), read(z);
tree1::addedge(x, y, z);
}
for(int i = 1, x, y, z; i < n; i++){
read(x), read(y), read(z);
tree2::addedge(x, y, z);
}
for(int i = 1, x, y, z; i < n; i++){
read(x), read(y), read(z);
tree3::addedge(x, y, z);
}
tree3::realmain();
tree2::realmain();
tree1::realmain();
cout << ANS << endl;
return 0;
}