异象石 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。
        </article>

题解

把有异象石的点按照其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;
}

3991: [SDOI2015]寻宝游戏

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 2219  Solved: 1133
[Submit][Status][Discuss]

Description

小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物

Input

第一行,两个整数N、M,其中M为宝物的变动次数。

接下来的N-1行,每行三个整数x、y、z,表示村庄x、y之间有一条长度为z的道路。
接下来的M行,每行一个整数t,表示一个宝物变动的操作。若该操作前村庄t内没有宝物,则操作后村庄内有宝物;若该操作前村庄t内有宝物,则操作后村庄内没有宝物。

Output

M行,每行一个整数,其中第i行的整数表示第i次操作之后玩家找到所有宝物需要行走的最短路程。若只有一个村庄内有宝物,或者所有村庄内都没有宝物,则输出0。

Sample Input

4 5

1 2 30

2 3 50

2 4 60

2

3

4

2

1

Sample Output

0

100

220

220

280

HINT

1<=N<=100000

1<=M<=100000
对于全部的数据,1<=z<=10^9

Source

[Submit][Status][Discuss]

HOME
Back


题解

这个每条边要走两次,选他们构成的虚树上的那个点都无所谓。实际上就是上一道题,只不过答案不用除以2.

CH#56C 异象石 和 BZOJ3991 [SDOI2015]寻宝游戏的更多相关文章

  1. [BZOJ3991][SDOI2015]寻宝游戏

    [BZOJ3991][SDOI2015]寻宝游戏 试题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择 ...

  2. [bzoj3991][SDOI2015]寻宝游戏_树链的并_倍增lca_平衡树set

    寻宝游戏 bzoj-3991 SDOI-2015 题目大意:题目链接. 注释:略. 想法:我们发现如果给定了一些点有宝物的话那么答案就是树链的并. 树链的并的求法就是把所有点按照$dfs$序排序然后相 ...

  3. CH#56C 异象石

    一道LCA 原题链接 先跑一边\(dfs\),求出每个节点的时间戳,如果我们将有异象石的节点按时间戳从小到大的顺序排列,累加相邻两节点之间的距离(首尾相邻),会发现总和就是答案的两倍. 于是我们只需要 ...

  4. bzoj3991: [SDOI2015]寻宝游戏--DFS序+LCA+set动态维护

    之前貌似在hdu还是poj上写过这道题. #include<stdio.h> #include<string.h> #include<algorithm> #inc ...

  5. bzoj3991 [Sdoi2015]寻宝游戏 set动态维护虚树+树链求并

    题目大意:支持多次操作,增加或删除一个关键点 动态维护虚树边权和*2 分析:可以用树链求并的方法,最后减去虚树的根到1距离 注意到树链求并是所有点到根距离-所有dfn序相邻两点的LCA到根距离 找df ...

  6. 【dfs序】【set】bzoj3991 [Sdoi2015]寻宝游戏

    在考试代码的基础上稍微改改就a了……当时为什么不稍微多想想…… 插入/删除一个新节点时就把其dfn插入set/从set中删除. 当前的答案就是dfn上相邻的两两节点的距离和,再加上首尾节点的距离. 比 ...

  7. BZOJ3991 [SDOI2015]寻宝游戏 【dfs序 + lca + STL】

    题目 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ...

  8. bzoj3991 [SDOI2015]寻宝游戏 树链的并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3991 题解 貌似这个东西叫做树链的并,以前貌似写过一个类似的用来动态维护虚树. 大概就是最终的 ...

  9. 【BZOJ3991】[SDOI2015]寻宝游戏 树链的并+set

    [BZOJ3991][SDOI2015]寻宝游戏 Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩 ...

随机推荐

  1. Java图形界面实战案例——实现打字母游戏

    实现打字母的游戏 这次这个案例能够说是头几次所讲的内容的一个技术汇总,主要是 运用了几大块的知识.我们先来定义一下案例的背景:在一个300*400的窗口上.有10个随机产生的字母下落,在键盘上敲击字母 ...

  2. Unity3d 中文菜单

  3. 用javascript简单写的判断电话号码

    在很多网站注册的时候,需要我们填写电话号码,本来想糊弄一下,但是还不行,一直提示不正确,我去网上搜了很多,正则表达式,发现有很多不对的, 最后写了一个简单的,但是比较实用的 首先是html部分的内容 ...

  4. 记录-项目java项目框架搭建的一些问题(maven+spring+springmvc+mybatis)

    伴随着项目框架的落成后,本以为启动就能成功的,but.... 项目启动开始报错误1:java.lang.ClassNotFoundException: org.springframework.web. ...

  5. 从HttpServletRequest获取POST数据的代码

    我们经常需要从HttpServletRequest对象获取POST请求的数据,下面给出简练的代码共大家参考 StringBuffer jb = new StringBuffer(); String l ...

  6. LeetCode:移除K位数字【402】

    LeetCode:移除K位数字[402] 题目描述 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. nu ...

  7. 更改node版本

    npm install -g n n stable 或 n v4.5.0

  8. platform-tools

    platform-tools包含开发app的平台依赖的开发和调试工具,包括 adb.fastboot等 android sdk里的各目录作用 AVD Manager.exe:虚拟机管理工具,用于建立和 ...

  9. 【leetcode刷题笔记】Longest Common Prefix

    Write a function to find the longest common prefix string amongst an array of strings. 题解:以strs[0]为模 ...

  10. CSS3环形动画菜单

    在线演示 本地下载