「SDOI2015」寻宝游戏
传送门
Luogu
解题思路
发现一个性质:
对于所有的宝藏点 \({a_1,a_2...a_k}\) ,按照dfs序递增排列,答案就是:
\(dis(a_1, a_2) + dis(a_2, a_3) + \cdots + dis(a_{k-1}, a_k) + dis(a_k, a_1)\)
考虑加入一个点的贡献:
假设加入的点是 \(u\),那么贡献就是 \(dis(L, u) + dis(R, u) - dis(L, R)\)
其中 \(L, R\) 分别是 \(u\) 点的对应dfs序的前驱和后继。
这个应该挺好理解的。
然后我们搞一个 set 就可以维护了。
细节注意事项
- 咕咕咕
参考代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#include <set>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= (c == '-'), c = getchar();
while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
s = f ? -s : s;
}
typedef long long LL;
const int _ = 100010;
int tot, head[_], nxt[_ << 1], ver[_ << 1], w[_ << 1];
inline void Add_edge(int u, int v, int d)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v, w[tot] = d; }
int n, m, num, vis[_]; LL dis[_];
int fa[_], siz[_], dep[_], top[_], son[_], dfn[_], id[_];
set < int > s;
set < int > ::iterator it;
inline void dfs1(int u, int f) {
fa[u] = f, dep[u] = dep[f] + 1;
siz[u] = 1, id[dfn[u] = ++num] = u;
for (rg int v, i = head[u]; i; i = nxt[i])
if (!dep[v = ver[i]]) {
dis[v] = dis[u] + w[i];
dfs1(v, u), siz[u] += siz[v];
if (siz[son[u]] < siz[v]) son[u] = v;
}
}
inline void dfs2(int u, int topf) {
top[u] = topf;
if (!son[u]) return; dfs2(son[u], topf);
for (rg int v, i = head[u]; i; i = nxt[i])
if (!top[v = ver[i]]) dfs2(v, v);
}
inline int LCA(int x, int y) {
int fx = top[x], fy = top[y];
while (fx != fy) {
if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);
x = fa[fx], fx = top[x];
}
return dep[x] < dep[y] ? x : y;
}
inline LL dist(int x, int y) { return dis[x] + dis[y] - 2 * dis[LCA(x, y)]; }
int main() {
#ifndef ONLINE_JUDGE
freopen("in.in", "r", stdin);
#endif
read(n), read(m);
for (rg int u, v, d, i = 1; i < n; ++i)
read(u), read(v), read(d), Add_edge(u ,v, d), Add_edge(v, u, d);
dfs1(1, 0), dfs2(1, 1);
LL ans = 0;
while (m--) {
int x, d; read(x), d = dfn[x];
if (!vis[x]) s.insert(d);
int l = id[(it = s.lower_bound(d)) == s.begin() ? *--s.end() : *--it];
int r = id[(it = s.upper_bound(d)) == s.end() ? *s.begin() : *it];
if (vis[x]) s.erase(d);
LL delta = dist(l, x) + dist(r, x) - dist(l, r);
if (vis[x]) ans -= delta, vis[x] = 0;
else ans += delta, vis[x] = 1;
printf("%lld\n", ans);
}
return 0;
}
完结撒花 \(qwq\)