异象石

题目描述

思路

一本通的描述比较详细
比较好的博客

代码

#include <cstdio>
#include <cstring>
#include <set>
#include <iterator>
#define FOR(a, n) for(int i = 1; i <= (n); ++i)
using namespace std;

const int MAX = 1e5 + 5;
int n, m;
long long ans;
int head[MAX], ver[MAX << 1], edge[MAX << 1], nt[MAX << 1], ht; // 存储边相关
int dfn[MAX], cnt; // dfn序相关
int f[MAX][21], dep[MAX]; // lca相关
long long dist[MAX];
set<pair<int, int> > st;
set<pair<int, int> >::iterator it;
void add(int x, int y, int z) {
    nt[++ht] = head[x], head[x] = ht, ver[ht] = y, edge[ht] = z;
}

void dfs_lca(int x, int u, int z) {
    dep[x] = dep[u] + 1;
    dfn[x] = ++cnt;
    dist[x] = dist[u] + z;
    f[x][0] = u;
    for (int i = 1; i < 21; ++i) {
        f[x][i] = f[f[x][i - 1]][i - 1];
    }
    for (int i = head[x], j, k; i; i = nt[i]) {
        j = ver[i], k = edge[i];
        if (j == u) continue;
        dfs_lca(j, x, k);
    }
}

int lca(int x, int y) {
    int X = x, Y = y;
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 20; i >= 0; --i) {
        if (dep[f[x][i]] >= dep[y]) {
            x = f[x][i];
        }
    }
    if (x == y) return x;
    for (int i = 20; i >= 0; --i) {
        if (f[x][i] != f[y][i]) {
            x = f[x][i], y = f[y][i];
        }
    }
    // printf("lca: %d %d %d\n", X, Y, f[x][0]);
    return f[x][0];
}

long long path(int x, int y) {
    return dist[x] + dist[y] - (dist[lca(x, y)] << 1);
}

inline int read() {
    int s = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
    return s;
}

void show() {
    printf("%d %d\n", n, m);
    puts("dep:");
    FOR(dep, n) printf("%d ", dep[i]); puts("");
    puts("dfn");
    FOR(dfn, n) printf("%d ", dfn[i]); puts("");
    puts("dist");
    FOR(dist, n) printf("%lld ", dist[i]); puts("");
    puts("fa");
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", f[i][j]);
        }
        puts("");
    }
}

int main() {
    n = read();
    for (int i = 1, a, b, c; i < n; ++i) {
        a = read(), b = read(), c = read();
        add(a, b, c), add(b, a, c);
    }
    m = read();
    dfs_lca(1, 0, 0);
    // show();
    char ch[5];
    for (int i = 1, j; i <= m; ++i) {
        scanf("%s", ch);
        // puts(ch);
        pair<int, int> l, r, te;
        if (strcmp(ch, "+") == 0) {
            j = read();
            te = make_pair(dfn[j], j);
            if (st.size() != 0) {
                it = (st.lower_bound(te));
                if (it == st.begin()) it = st.end();
                l = *(--it);
                // printf("L +: %d %d\n", l.first, l.second);
                it = st.upper_bound(te);
                if (it == st.end()) r = *st.begin();
                else r = *it;
                // printf("R +: %d %d\n", r.first, r.second);
                ans = ans - path(l.second, r.second) + path(l.second, j) + path(r.second, j);
            }
            st.insert(make_pair(dfn[j], j));
        } else if (strcmp(ch, "-") == 0) {
            j = read();
            te = make_pair(dfn[j], j);
            st.erase(te);
            if (st.size() == 0) {
                ans = 0;
                continue;
            }
            it = st.lower_bound(te);
            if (it == st.begin()) it = st.end();
            l = *(--it);
            // printf("L -: %d %d\n", l.first, l.second);
            it = st.upper_bound(te);
            if (it == st.end()) r = *st.begin();
            else r = *it;
            // printf("R -: %d %d\n", r.first, r.second);
            ans = ans + path(l.second, r.second) - path(l.second, j) - path(r.second, j);
        } else {
            printf("%lld\n", ans / 2);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/liuzz-20180701/p/11505157.html

时间: 2024-11-06 03:41:36

异象石的相关文章

【NOIP模拟赛】异象石

Description Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上有N个点,有N-1条双向边把它们连通起来.起初地图上没有任何异象石,在接下来的M个时刻中,每个时刻会发生以下三种类型的事件之一: 1.地图的某个点上出现了异象石(已经出现的不会再次出现): 2.地图某个点上的异象石被摧毁(不会摧毁没有异象石的点): 3.向玩家询问使所有异象石所在的点连通的边集的总长度最小是多少. 请你作为玩家回答这

Luogu P3320 [SDOI2015]寻宝游戏 / 异象石 【LCA/set】

期末考试结束祭! 在期末考试前最后一发的测试中,异象石作为第二道题目出现QAQ.虽然知道是LCA图论,但还是敲不出来QAQ. 花了两天竞赛课的时间搞懂(逃 异象石(stone.pas/c/cpp)题目描述Adera 是 Microsoft 应用商店中的一款解谜游戏.异象石是进入 Adera 中异时空的引导物,在 Adera 的异时空中有一张地图.这张地图上有 N 个点,有 N-1 条双向边把它们连通起来.起初地图上没有任何异象石,在接下来的 M个时刻中,每个时刻会发生以下三种类型的事件之一:1.

一本通1554【例 3】异象石

1554:[例 3]异象石 时间限制: 1000 ms         内存限制: 524288 KB 题目描述 原题来自:Contest Hunter Round #56 在 Adera 的异时空中有一张地图.这张地图上有 N 个点,有 N?1 条双向边把它们连通起来.起初地图上没有任何异象石,在接下来的 M 个时刻中,每个时刻会发生以下三种类型的事件之一: 地图的某个点上出现了异象石(已经出现的不会再次出现): 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点): 向玩家询问使所有异象石所

「一本通 4.4 例 3」异象石 与 [SDOI2015]寻宝游戏

这两个题差不多先说异象石把 主要是找到本题规律,将所加入的点按dfs序排序,记录为a[1],a[2]..a[n]则当前的答案为每个点与前一个点的距离(第一个点则与最后一点) 当然要动态维护答案,每加入一个点就+与前驱的距离+与后驱的距离-前驱与后驱的距离(删点的话ans减去这个值就好 不过异象石最后的答案要/2: 至于维护的话用set就好 1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 cons

CH#56C 异象石

异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上有N个点,有N-1条双向边把它们连通起来.起初地图上没有任何异象石,在接下来的M个时刻中,每个时刻会发生以下三种类型的事件之一: 1. 地图的某个点上出现了异象石(已经出现的不会再次出现): 2. 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点): 3. 向玩家询问使所有异象石所在的点连通的边集

异象石/[SDOI2015]寻宝游戏

AcWing 异象石 洛咕 寻宝游戏 题意:Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图. 这张地图上有\(N(N<=1e5)\)个点,有\(N-1\)条双向边把它们连通起来. 起初地图上没有任何异象石,在接下来的\(M(M<=1e5)\)个时刻中,每个时刻会发生以下三种类型的事件之一: 地图的某个点上出现了异象石(已经出现的不会再次出现); 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点); 向玩家询问

异象石——最近公共祖先

题目链接: https://www.acwing.com/problem/content/357/ 题意: 给出一个树上节点的集合,动态加入或者删除节点,询问连通所有节点的最小边集的权值之和. 解法: 把集合中的节点按照时间戳排序,每相邻两个节点距离以及首尾节点距离累加,累加之和为答案的两倍.(目前不会证明) 节点排序用set维护,首先加入0和inf,以便修改. 代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef lo

CH Round #56 - 国庆节欢乐赛解题报告

最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树,其中一些树上结有能够产生能量的魔力水果.已知每个水果的位置(Xi,Yi)以及它能提供的能量Ci.然而,魔幻森林在某些时候会发生变化:(1) 有两行树交换了位置.(2) 有两列树交换了位置.当然,树上结有的水果也跟随着树一起移动.不过,只有当两行(列)包含的魔力水果数都大于0,或者两行(列)都没有魔

hdu 5088 高斯消元n堆石子取k堆石子使剩余异或值为0

http://acm.hdu.edu.cn/showproblem.php?pid=5088 求能否去掉几堆石子使得nim游戏胜利 我们可以把题目转化成求n堆石子中的k堆石子数异或为0的情况数.使用x1---xn表示最终第i堆石子到底取不取(1取,0不取),将每堆石子数画成2进制的形式,列成31个方程来求自由变元数,最后由于自由变元能取1.0两种状态,所以自由变元数多于0即可输出Yes. 注意有40+个方程,因为A[I]<=1e12.... #include <cstdio> #incl