题解:P11324 【MX-S7-T2】「SMOI-R2」Speaker
BFS + 树链剖分
题目描述
原题链接
前言
什么 DP,什么换根,不会写,怎么办?
其实这道题根本不需要!
只需要简单的 BFS 也可轻松解决!
解题思路
我们将
最后我们得到的
BFS 代码实现如下:
for (int i = 1; i <= n; ++i)
bfs[i] = c[i];
for (int i = 1; i <= n; ++i)
{
queue<int> q;
q.push(i);
while (!q.empty())
{
int w = q.front(); q.pop();
for (Edge j : mp[w])
if (bfs[j.to] < bfs[w] - j.ct * 2)
{
bfs[j.to] = bfs[w] - j.ct * 2;
q.push(j.to);
}
}
}
然后我们使用树链剖分 + ST 表,维护区间
代码实现
AC 记录
/*BFS + Heavy-Light Decomposition*/
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 2e5 + 10;
struct Edge {
int to, ct;
bool operator< (const Edge &rhs) const {
return rhs.ct < ct;
}
};
vector<Edge> mp[MAXN];
int c[MAXN];
int bfs[MAXN], ans[MAXN], dis[MAXN], pre[MAXN];
int f[MAXN], sz[MAXN],son[MAXN], top[MAXN], id[MAXN];
int st[MAXN][20 + 5];
int cnt;
void dfs1(int x, int fa)
{
dis[x] = dis[fa] + 1;
f[x] = fa;
int maxson = -1;
for (Edge i : mp[x])
if (i.to != fa)
{
pre[i.to] = pre[x] + i.ct;
dfs1(i.to, x);
sz[x] += sz[i.to];
if (sz[i.to] > maxson)
{
maxson = sz[i.to];
son[x] = i.to;
}
}
sz[x]++;
}
void dfs2(int x, int ntop)
{
id[x] = ++cnt;
top[x] = ntop;
if (!son[x]) return;
dfs2(son[x], ntop);
for (Edge i : mp[x])
{
if (i.to == f[x] || i.to == son[x]) continue;
dfs2(i.to, i.to);
}
}
int ask(int l, int r)
{
int k = log(r - l + 1) / log(2);
return max(st[l][k], st[r - (1 << k) + 1][k]);
}
signed main()
{
//freopen("speaker.in", "r", stdin);
//freopen("speaker.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; ++i)
cin >> c[i];
for (int i = 1; i <= n - 1; ++i)
{
int u, v, ct;
cin >> u >> v >> ct;
mp[u].push_back({v, ct});
mp[v].push_back({u, ct});
}
for (int i = 1; i <= n; ++i)
bfs[i] = c[i];
for (int i = 1; i <= n; ++i)//BFS
{
queue<int> q;
q.push(i);
while (!q.empty())
{
int w = q.front(); q.pop();
for (Edge j : mp[w])
if (bfs[j.to] < bfs[w] - j.ct * 2)
{
bfs[j.to] = bfs[w] - j.ct * 2;
q.push(j.to);
}
}
}
dfs1(1, 1);
dfs2(1, 1);
for (int i = 1; i <= n; ++i)
ans[id[i]] = bfs[i];
for (int i = 1; i <= n; ++i)//ST
st[i][0] = ans[i];
int maxk = log(n) / log(2) + 1;
for (int j = 1; j <= maxk; ++j)
for (int i = 1; i + (1 << j) <= n + 1; ++i)
st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
for (int i = 1; i <= q; ++i)
{
int x, y;
cin >> x >> y;
int val = LLONG_MIN;
int fx = x, fy = y;
while (top[x] != top[y])
{
if (dis[top[x]] < dis[top[y]]) swap(x, y);
val = max(val, ask(id[top[x]], id[x]));
x = f[top[x]];
}
if (dis[x] > dis[y]) swap(x, y);
val = max(val, ask(id[x], id[y]));
val = max(val, ans[id[x]]);
int dxy = pre[fx] + pre[fy] - 2 * pre[x];
cout << c[fx] + val + c[fy] - dxy << endl;
}
return 0;
}
特别鸣谢
感谢 @consequence协助完成树链剖分的代码。