树的直径
结论:树上的点到树的直径的两个端点的距离的最大值即为该点到树中所有点的最大值。
F - Minimum Maximum Distance(有标记的直径)
Codeforces Round 903 (Div. 3)A~F_hjing小靖的博客-CSDN博客
在标记点的树的直径,同理可根据树的直径性质证明。
F - Gardening Friends(直径减去换根距离)
#include<bits/stdc++.h>
#define double long double
#define int long long
using namespace std;
const int N = 1e6;
void solve()
{
int n, k, c; cin >> n >> k >> c;
vector<vector<int>>adj(n + 1);
for(int i = 0; i < n - 1; i ++)
{
int u, v; cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
vector<int>dis(n + 1);
auto bfs = [&](int x)
{
dis.assign(n + 1, -1);
queue<int>q;
q.push(x);
dis[x] = 0;
while(q.size())
{
int u = q.front();
q.pop();
for(auto v : adj[u])
{
if(dis[v] != -1) continue;
dis[v] = dis[u] + 1;
q.push(v);
}
}
int t = -1;
for(int i = 1; i <= n; i ++) if(t == - 1 || dis[t] < dis[i]) t = i;
return t;
};
int a = bfs(1); auto d0 = dis;
int b = bfs(a); auto da = dis;
bfs(b); auto db = dis;
int ans = 0;
for(int i = 1; i <= n; i ++)
{
ans = max(ans, max(da[i], db[i]) * k - d0[i] * c);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t; cin >> t;
while (t--) solve();
}
换根dp
[POI2008] STA-Station - 洛谷(深度之和最大的点)
设u为v的父节点,那么每次把子节点换为根的转移方程,f[v] = f[u] - size[v] + n - size[v]
#include<bits/stdc++.h>
#define double long double
#define int long long
using namespace std;
const int N = 1e6;
void solve()
{
int n; cin >> n;
vector<vector<int>>adj(n + 1);
for(int i = 0; i < n - 1; i ++)
{
int u, v; cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
vector<int>f(n + 1), size(n + 1), dep(n + 1);
auto dfs1 = [&](auto dfs1, int u, int fa) -> void
{
for(auto v : adj[u])
{
if(v == fa) continue;
dep[v] = dep[u] + 1;
dfs1(dfs1, v, u);
size[u] += size[v];
}
size[u] ++;
};
dfs1(dfs1, 1, -1);
for(int i = 1; i <= n; i ++) f[1] += dep[i];
auto dfs2 = [&](auto dfs2, int u, int fa) -> void
{
for(auto v : adj[u])
{
if(v == fa) continue;
f[v] = f[u] - size[v] + n - size[v];
dfs2(dfs2, v, u);
}
};
dfs2(dfs2, 1, -1);
int t = -1;
for(int i = 1; i <= n; i ++) if(t == -1 || f[i] > f[t]) t = i;
cout << t << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while (t--) solve();
}
D - Tree XOR(位运算)
f[v] = f[u] - (a[u] ^ a[v]) * size[v] + (a[u] ^ a[v]) * (n - size[v]);
#include<bits/stdc++.h>
#define double long double
#define int long long
using namespace std;
const int N = 1e6;
void solve()
{
int n; cin >> n;
vector<int>a(n + 1);
for(int i = 1; i <= n; i ++) cin >> a[i];
vector<vector<int>>adj(n + 1);
for(int i = 0; i < n - 1; i ++)
{
int u, v; cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
vector<int>f(n + 1), size(n + 1);
auto dfs1 = [&](auto dfs1, int u, int fa) -> void
{
for(auto v : adj[u])
{
if(v == fa) continue;
dfs1(dfs1, v, u);
size[u] += size[v];
f[1] += (a[u] ^ a[v]) * size[v];
}
size[u] ++;
};
dfs1(dfs1, 1, -1);
auto dfs2 = [&](auto dfs2, int u, int fa) -> void
{
for(auto v : adj[u])
{
if(v == fa) continue;
f[v] = f[u] - (a[u] ^ a[v]) * size[v] + (a[u] ^ a[v]) * (n - size[v]);
dfs2(dfs2, v, u);
}
};
dfs2(dfs2, 1, -1);
for(int i = 1; i <= n; i ++) cout << f[i] << " ";
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; cin >> t;
while (t--) solve();
}
[USACO10MAR] Great Cow Gathering G - 洛谷
f[v] = f[u] - w * size[v] + w * (cnt - size[v]);
#include<bits/stdc++.h>
#define double long double
#define int long long
using namespace std;
const int N = 1e6;
struct node
{
int v, w;
};
void solve()
{
int n, cnt = 0; cin >> n;
vector<int>a(n + 1);
for(int i = 1; i <= n; i ++) cin >> a[i], cnt += a[i];
vector<vector<node>>adj(n + 1);
for(int i = 0; i < n - 1; i ++)
{
int u, v, w; cin >> u >> v >> w;
adj[u].push_back({v, w});
adj[v].push_back({u, w});
}
vector<int>f(n + 1), size(n + 1);
auto dfs1 = [&](auto dfs1, int u, int fa) -> void
{
for(auto i : adj[u])
{
int v = i.v, w = i.w;
if(v == fa) continue;
dfs1(dfs1, v, u);
size[u] += size[v];
f[1] += w * size[v];
//cout << v << " " << w << " " << size[v] << '\n';
}
size[u] += a[u];
};
dfs1(dfs1, 1, -1);
auto dfs2 = [&](auto dfs2, int u, int fa) -> void
{
for(auto i : adj[u])
{
int v = i.v, w = i.w;
if(v == fa) continue;
f[v] = f[u] - w * size[v] + w * (cnt - size[v]);
dfs2(dfs2, v, u);
}
};
dfs2(dfs2, 1, -1);
int t = -1;
for(int i = 1; i <= n; i ++)
{
//cout << f[i] << '\n';
if(t == -1 || f[i] < f[t]) t = i;
}
cout << f[t] << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while (t--) solve();
}
E - Tree Painting(思维/跟树的最大深度实现一样)
从根往下取是最优的
#include<bits/stdc++.h>
#define double long double
#define int long long
using namespace std;
const int N = 1e6;
struct node
{
int v, w;
};
void solve()
{
int n; cin >> n;
vector<vector<int>>adj(n + 1);
for(int i = 0; i < n - 1; i ++)
{
int u, v, w; cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
vector<int>f(n + 1), size(n + 1);
auto dfs1 = [&](auto dfs1, int u, int fa) -> void
{
for(auto v : adj[u])
{
//int v = i.v, w = i.w;
if(v == fa) continue;
dfs1(dfs1, v, u);
size[u] += size[v];
}
size[u] += 1;
f[1] += size[u];
};
dfs1(dfs1, 1, -1);
auto dfs2 = [&](auto dfs2, int u, int fa) -> void
{
for(auto v : adj[u])
{
//int v = i.v, w = i.w;
if(v == fa) continue;
f[v] = f[u] - size[v] + (n - size[v]);
dfs2(dfs2, v, u);
}
};
dfs2(dfs2, 1, -1);
int t = -1;
for(int i = 1; i <= n; i ++)
{
if(t == -1 || f[i] > f[t]) t = i;
}
cout << f[t] << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1; //cin >> t;
while (t--) solve();
}