JZOJ1497 景点中心 题解
题目:#
数据范围以及样例解释:#
#
思路#
对于30%的数据,爱怎么做怎么做,我就不信你拿不到。
对于60%的数据,枚举所有的点作为根,以该点根做dfs可以求出每个点到根的距离dis[i],用每个点的学生人数dis[i]再加起来就是对应的答案,取个最小值即可。枚举O(n),dfs复杂度也是O(n),因此复杂度为O(n^2)。只能通过60%数据。
对于100%的数据,考虑换根法。即先随意定一点为根(也就是景点中心),并求出其对应答案。我们在60%的做法中,每枚举一个点都对其重新求一遍答案,这样子的效率极其低下,因为我们可以根据已有答案O(1)转移。若已知当前根为u的答案,我们将根变成u的儿子v,那么u的其他儿子的子树中的每个点,都要多走u到v的这段长度,而v的子树中的每个点,都会少走u到v的这段长度。于是我们可以先假设1为根,然后暴力求出其答案,同时求出sum[i]表示以1为根的情况下i的子树中的学生总数。设原来的答案是ret,换成v为根后答案就是ret+(sum[1]-sum[v])len[i]-sum[v]*len[i]。
复杂度就是O(n)
代码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
inline int read()
{
int x = 0, f = 0;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = 1;
for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ '0');
return f ? -x : x;
}
typedef long long ll;
const int N = 1e5 + 7;
int tot = 0, st[N], to[N << 1], nx[N << 1];
ll sum[N], a[N], len[N << 1], mi = 0;
int n, ans;
inline void add(int u, int v, int w) { to[++tot] = v, nx[tot] = st[u], len[tot] = (ll)w, st[u] = tot; }
void dfs(int u, int from)
{
sum[u] = a[u];
for (int i = st[u]; i; i = nx[i]) if (to[i] != from) dfs(to[i], u), sum[u] += sum[to[i]], mi += sum[to[i]] * len[i];
}
void getans(int u, int from, ll ret)
{
if (ret < mi) mi = ret, ans = u;
for (int i = st[u]; i; i = nx[i])
if (to[i] != from)
getans(to[i], u, ret - sum[to[i]] * len[i] + (sum[1] - sum[to[i]]) * len[i]);
}
int main()
{
n = read();
for (int i = 1; i <= n; i++) a[i] = (ll)read();
for (int i = 1, u, v, w; i < n; i++) u = read(), v = read(), w = read(), add(u, v, w), add(v, u, w);
dfs(1, 0);
ans = 1;
getans(1, 0, mi);
printf("%d\n%lld\n", ans, mi);
return 0;
}
作者:zjlcnblogs
出处:https://www.cnblogs.com/zjlcnblogs/p/9277862.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步