「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\)

猜你喜欢

转载自www.cnblogs.com/zsbzsb/p/11746534.html
今日推荐