CH#56C 异象石

异象石 CH Round #56 - 国庆节欢乐赛

描述

Adera是Microsoft应用商店中的一款解谜游戏。

异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图。这张地图上有N个点,有N-1条双向边把它们连通起来。起初地图上没有任何异象石,在接下来的M个时刻中,每个时刻会发生以下三种类型的事件之一:

1. 地图的某个点上出现了异象石(已经出现的不会再次出现);

2. 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点);

3. 向玩家询问使所有异象石所在的点连通的边集的总长度最小是多少。

请你作为玩家回答这些问题。

输入格式

第一行有一个整数N,表示点的个数。

接下来N-1行每行三个整数x,y,z,表示点x和y之间有一条长度为z的双向边。

第N+1行有一个正整数M。

接下来M行每行是一个事件,事件是以下三种格式之一:

+ x    表示点x上出现了异象石

- x    表示点x上的异象石被摧毁

?     表示询问使当前所有异象石所在的点连通所需的边集的总长度最小是多少。

输出格式

对于每个 ? 事件,输出一个整数表示答案。

样例输入

6
1 2 1
1 3 5
4 1 7
4 5 3
6 4 2
10
+ 3
+ 1
?
+ 6
?
+ 5
?
- 6
- 3
?

样例输出

5
14
17
10

数据范围与约定

  • 对于30%的数据,1 ≤ n, m ≤ 1000。
  • 对于另20%的数据,地图是一条链,或者一朵菊花。
  • 对于100%的数据,1 ≤ n, m ≤ 10^5, 1 ≤ x, y ≤ n, x ≠ y, 1 ≤ z ≤ 10^9。

题解

把有异象石的点按照其DFS序大小写作一个环形序列,该序列中相邻的数的距离之和就是答案的2倍。

用set维护这个序列,用一个变量记录答案,插入or摧毁时在序列中插入or删除数,并更改答案即可。求距离可以用倍增lca。

时间复杂度\(O((n+m)\log n)\)

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
    for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;
typedef pair<int,int> pii;

co int N=1e5+1;
int n,m,t,f[N][18],dep[N],dfn[N],tot;
vector<pii> e[N];
ll d[N],ans;
set<pii> st;
typedef set<pii>::iterator it;
void dfs(int x){
    dfn[x]=++tot;
    for(int i=0,y;i<e[x].size();++i){
        if(dep[y=e[x][i].first]) continue;
        dep[y]=dep[x]+1;
        d[y]=d[x]+e[x][i].second;
        f[y][0]=x;
        for(int j=1;j<=t;++j) f[y][j]=f[f[y][j-1]][j-1];
        dfs(y);
    }
}
int lca(int x,int y){
    if(dep[x]>dep[y]) swap(x,y);
    for(int i=t;i>=0;--i)
        if(dep[f[y][i]]>=dep[x]) y=f[y][i];
    if(x==y) return x;
    for(int i=t;i>=0;--i)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
il ll path(int x,int y){
    return d[x]+d[y]-2*d[lca(x,y)];
}
il void insert(int x){
    st.insert(pii(dfn[x],x));
    it l=st.find(pii(dfn[x],x));
    l=l==st.begin()?--st.end():--l;
    it r=st.find(pii(dfn[x],x));
    r=r==--st.end()?st.begin():++r;
    ans-=path(l->second,r->second);
    ans+=path(l->second,x)+path(x,r->second);
}
il void remove(int x){
    it l=st.find(pii(dfn[x],x));
    l=l==st.begin()?--st.end():--l;
    it r=st.find(pii(dfn[x],x));
    r=r==--st.end()?st.begin():++r;
    ans-=path(l->second,x)+path(x,r->second);
    ans+=path(l->second,r->second);
    st.erase(pii(dfn[x],x));
}
int main(){
    read(n);
    for(int i=1,x,y,z;i<n;++i){
        read(x),read(y),read(z);
        e[x].push_back(pii(y,z)),e[y].push_back(pii(x,z));
    }
    t=log(n)/log(2)+1;
    dep[1]=1,dfs(1);
    for(read(m);m--;){
        char s[2];scanf("%s",s);
        if(s[0]=='?') printf("%lld\n",ans/2);
        else{
            int x=read<int>();
            s[0]=='+'?insert(x):remove(x);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/autoint/p/10935047.html

时间: 2024-08-30 18:13:25

CH#56C 异象石的相关文章

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

异象石/[SDOI2015]寻宝游戏

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

【NOIP模拟赛】异象石

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

异象石

题目描述 思路 一本通的描述比较详细 比较好的博客 代码 #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

异象石——最近公共祖先

题目链接: 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,或者两行(列)都没有魔

17.11.17 递归作业

习题(15-1) 前缀表达式 (1010) 描述 前缀表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的前缀表示法为+ 2 3.前缀表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的前缀表示法为* + 2 3 4.本题求解前缀表达式的值,其中运算符包括+ - * /四个. 关于输入 输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数. 关于输出 输出为一行,表达式的值.  可直接用printf("%f\n", v