main
黄海 2 years ago
parent 281abd84d2
commit bb84f7fd9f

@ -1,85 +1,75 @@
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
char c = getchar();
ll a = 0, b = 1;
for (; c < '0' || c > '9'; c = getchar())
if (c == '-') b = -1;
for (; c >= '0' && c <= '9'; c = getchar()) a = a * 10 + c - 48;
return a * b;
const int N = 500010, M = N << 1;
#define int long long
int n, K;
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
struct edge {
ll next, to, v;
} e[1000501];
ll head[1000501], tot, n, k, vis[1000501], f[1000001], ans[1000001], sum[1000001];
ll len[1000501], slen[1000501], dis[1000501], sdis[1000501]; // ·Ö±ðÊÇÀëi×îÔ¶µÄµãºÍ´ÎÔ¶µÄµãµÄ¾àÀ룬ÒÔ¼°ÕâÌõÁ´µÄµÚÒ»¸öµãÔÚÄÄÀï
ll up[1000501];
inline void add(ll i, ll j, ll k) {
e[++tot].next = head[i];
e[tot].to = j;
e[tot].v = k;
head[i] = tot;
}
void dfsfirst(ll x, ll fa) {
if (vis[x]) sum[x]++;
for (ll i = head[x]; i != 0; i = e[i].next) {
ll u = e[i].to;
if (u == fa) continue;
dfsfirst(u, x);
if (sum[u]) {
ll now = len[u] + e[i].v;
f[x] += f[u] + e[i].v * 2;
if (len[x] < now)
sdis[x] = dis[x],
dis[x] = u,
slen[x] = len[x],
len[x] = now;
else if (slen[x] < now)
sdis[x] = u,
slen[x] = now;
int pos[N];
int sz[N], g[N], f[N];
int len[N], id[N], slen[N];
void dfs1(int u, int fa) {
if (pos[u]) sz[u] = 1;
for (int i = Head[u]; i; i = Edge[i].next) {
int v = Edge[i].to, w = Edge[i].val;
if (v == fa) continue;
dfs1(v, u);
if (sz[v]) {
g[u] += g[v] + 2 * w;
int now = len[v] + w;
if (now >= len[u])
slen[u] = len[u], len[u] = now, id[u] = v;
else if (now > slen[u])
slen[u] = now;
}
sum[x] += sum[u];
sz[u] += sz[v];
}
}
void dfsecond(ll x, ll fa) // ¸üÐÂÈ«¾Ö´ð°¸
{
for (ll i = head[x]; i != 0; i = e[i].next) {
ll u = e[i].to;
if (u == fa) continue;
if (sum[u] == 0) {
ans[u] = ans[x] + e[i].v * 2;
up[u] = max(up[x], len[x]) + e[i].v;
} else if (sum[u] == k) {
ans[u] = f[u];
up[u] = 0;
} else {
ans[u] = ans[x];
if (dis[x] == u)
up[u] = max(up[x], slen[x]) + e[i].v; // Ϊʲô´Î³¤¾Í²»»á¾­¹ý,ÒòΪÎÒÉÏÃæÃ¿Ìõ¶¼Ö»È¡ÁËÒ»Ìõ×î´óÖµ°¡¡£¡£¡£
else
up[u] = max(up[x], len[x]) + e[i].v;
}
dfsecond(u, x);
void dfs2(int u, int fa) {
for (int i = Head[u]; i; i = Edge[i].next) {
int v = Edge[i].to, w = Edge[i].val;
if (v == fa) continue;
if (!sz[v])
f[v] = f[u] + 2 * w, len[v] = len[u] + w;
else if (K - sz[v]) {
f[v] = f[u];
if (id[u] != v && len[v] < len[u] + w)
slen[v] = len[v], len[v] = len[u] + w, id[v] = u;
else if (len[v] < slen[u] + w)
slen[v] = len[v], len[v] = slen[u] + w, id[v] = 1;
else if (slen[v] < len[u] + w && id[u] != v)
slen[v] = len[u] + w;
else if (slen[v] < slen[u] + w)
slen[v] = slen[u] + w;
} else
f[v] = g[v];
dfs2(v, u);
}
}
int main() {
n = read();
k = read();
for (ll i = 1; i < n; i++) {
ll a = read(), b = read(), c = read();
add(a, b, c);
add(b, a, c);
}
for (ll i = 1; i <= k; i++) {
vis[read()] = 1;
signed main() {
// 初始化链式前向星
memset(h, -1, sizeof h);
cin >> n >> K;
for (int i = 1; i < n; i++) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
dfsfirst(1, 0);
ans[1] = f[1];
up[1] = 0;
dfsecond(1, 0);
for (ll i = 1; i <= n; i++) {
cout << ans[i] - max(up[i], len[i]) << endl;
for (int i = 1; i <= K; i++) {
int x;
cin >> x;
pos[x] = 1;
}
return 0;
dfs1(1, 0);
f[1] = g[1];
dfs2(1, 0);
for (int i = 1; i <= n; i++) cout << f[i] - len[i] << endl;
}

@ -1,5 +1,3 @@
## 换根$DP$
换根$DP$,又叫二次扫描,是树形$DP$的一种。
@ -853,6 +851,7 @@ $5$个点, $4$条边。当以$4$为起点时, 得到最大流量为$26$。
- ② 因为$1$号节点没有向上的路径了,所以$g[1]=f[1]$
- ③ 从$1$号根节点出发, 扫描所有节点, 自顶往下进行更新$g$数组,$g[x]$代表以$x$为根节点的整棵树的最大总流量(**不光是向下,还要有向上的**)。
用$du$数组存节点的度,以便判断叶子结点:第一次搜索时,状态转移是如下代码所示:
- ① 如果$v$是叶子结点, $v$的子树的最大流就是 $f[u] + w[u][v]$ 这里的$w[u][v]$表示$u$ 到 $v$ 的流量,代码中用$w[i]$表示
- ② 如果$v$不是叶子结点, 流量就等于$v$的子树的最大流量和$u$到$v$的流量取最小值。
@ -960,9 +959,46 @@ int main() {
一棵树上有一些点有人,边有通过的长度,然后对于每个点,你从这个点出发经过所有人(不用回到原来位置)的最短时间。
其它人不会动,只有你去找人。
**思路**
https://www.luogu.com.cn/problem/solution/P6419
首先,第一眼,这是一道换根$dp$
接下来我们就要看两次$dfs$要处理什么
第一次$dfs$
按照换根$dp$的老套路,我们要处理子树里的信息
- $g[u]$:以 $u$ 为根的子树中从 $u$ 开始把所有家在这个子树内的人送回家 **并回到** $u$ **节点**的最短路程
- $sz[u]$:家在以 $u$ 为根的子树中的人数
显然,我们可以得到 $\displaystyle g[u]=\sum_{v \in son[u]} g[v]+2\times w_{u \rightarrow v}$,其中$v$是 $u$的子节点,且$sz_v \neq 0$
其中 $w$ 为边权
刚做这道题的我天真地以为这就是第一次 $dfs$ 需要处理的东西,当我写完之后测样例时,发现挂掉了,所以,我们还需要处理一些东西
我们手算了一遍样例,**发现我们的车可以送完人了之后不返回开始点**;也就是说再我们这么算回到起始点的数值之后还要 **减去一个最长链的长度**!
这里的 **最长链就表示离一个点最远的人的家**
令 $len[u]$ 表示:从 $u$ 开始的最长链,$id[u]$ 为从 $u$ 开始的最长链所经过的第一个节点(也就是 $u$ 的一个子节点或者 $u$ 的父亲节点)
令$slen[u]$表示:为从 $u$ 开始的次长链,次长链是干啥的待会再说
> **解释**$s:second$
当然了,第一次$dfs$我们还是只处理子树内的最长链,次长链
先放第一次$dfs$的代码:
Loading…
Cancel
Save