main
黄海 2 years ago
parent 6e81d4e4ee
commit 566a8539da

@ -1,40 +1,60 @@
#include <bits/stdc++.h> #include <bits/stdc++.h>
using namespace std; using namespace std;
#define LL long long const int N = 1e5 + 10, M = N << 1;
const int N = 1e5 + 10; const int INF = 0x3f3f3f3f;
vector<int> g[N];
int a[N]; // 链式前向星
int dp[N], siz[N]; int e[M], h[N], idx, w[M], ne[M];
int ans = 1e9; void add(int a, int b, int c = 0) {
void dfs1(int u, int fa, int dep) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
siz[u] = a[u]; }
for (auto v : g[u]) { int c[N];
int f[N], sz[N];
int ans = INF;
// 第一次dfs,获取在以1为根的树中:
// 1、每个节点分别有多少个子节点填充sz[]数组
// 2、获取到f[1],f[1]表示在1点设置医院的代价
// 获取到上面这一组+一个数据才能进行dfs2进行换根
void dfs1(int u, int fa, int step) {
sz[u] = c[u];
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (v == fa) continue; if (v == fa) continue;
dfs1(v, u, dep + 1); dfs1(v, u, step + 1);
siz[u] += siz[v]; sz[u] += sz[v];
} }
dp[1] += dep * a[u]; // 先算出1点的总代价 f[1] += step * c[u]; // 先算出1点的总代价
} }
void dfs2(int u, int fa) { void dfs2(int u, int fa) {
for (auto v : g[u]) { for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (v == fa) continue; if (v == fa) continue;
dp[v] = dp[u] + siz[1] - siz[v] * 2; f[v] = f[u] + sz[1] - sz[v] * 2;
dfs2(v, u); dfs2(v, u);
} }
ans = min(ans, dp[u]); ans = min(ans, f[u]);
} }
int main() { int main() {
// 初始化链式前向星
memset(h, -1, sizeof h);
int n; int n;
cin >> n; cin >> n;
for (int i = 1; i <= n; i++) { for (int i = 1; i <= n; i++) {
cin >> a[i]; cin >> c[i];
int u, v; int a, b;
cin >> u >> v; cin >> a >> b;
if (u > 0) g[i].push_back(u), g[u].push_back(i); if (a) add(a, i), add(i, a); // 是一个二叉树结构,与左右节点相链接,但有可能不存在左或右节点,不存在时,a或b为0
if (v > 0) g[i].push_back(v), g[v].push_back(i); if (b) add(b, i), add(i, b);
} }
// 1、准备运作
dfs1(1, 0, 0); dfs1(1, 0, 0);
dfs2(1, 0); // 换根 // 2、换根dp
cout << ans; dfs2(1, 0);
// 输出答案
cout << ans << endl;
return 0; return 0;
} }

@ -344,14 +344,15 @@ int main() {
**三、$O(N)$算法** **三、$O(N)$算法**
如果$n=1e6$,那么就要考虑换根$dp$了 如果$n=1e6$,那么就要考虑换根$dp$了
我们考虑相邻的医院是否存在转换关系 我们考虑相邻的医院是否存在转换关系,设其中一个医院为$u$(父节点),另一个为$v$(子节点)
设其中一个医院为u父节点另一个为v(子节点) 如果把$u$点的医院改为$v$点,则发现:
如果把u点的医院改为v点则发现 以$v$为根的子树的集合的所有人少走$1$步,但是另一集合的所有人要多走一步
以v为根的子树的集合的所有人少走1步但是另一集合的所有人要多走一步 设$sz[i]$表示以$i$为根节点的集合人的总数,$f[i]$表示在$i$点设置医院的代价,则可转换成:
设siz[i]表示以i为根节点的集合人的总数dp[i]表示在i点设置医院的代价则可转换成 $$\large f[v]=f[u]+(sz[1]-sz[v])-sz[v]=f[u]+sz[1]-2\times sz[v]$$
dp[v]=dp[u]+(siz[1]-siz[v])-siz[v]:其中siz[1]表示全部人的数量 > 其中$sz[1]$表示全部人的数量,一般也写做$n$
思路:
1.先算出1个点的代价之后dp换根直接转换 **思路**
先算出$1$个点的代价,之后$dp$换根直接转换
#### [$P2986$ $Great$ $Cow$ $Gathering$ $G$](https://www.luogu.com.cn/problem/P2986) #### [$P2986$ $Great$ $Cow$ $Gathering$ $G$](https://www.luogu.com.cn/problem/P2986)

Loading…
Cancel
Save