bzoj 3991: [SDOI2015]寻宝游戏
Description
小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物
Input
第一行,两个整数N、M,其中M为宝物的变动次数。
Output
M行,每行一个整数,其中第i行的整数表示第i次操作之后玩家找到所有宝物需要行走的最短路程。若只有一个村庄内有宝物,或者所有村庄内都没有宝物,则输出0。
Sample Input
1 2 30
2 3 50
2 4 60
2
3
4
2
1
Sample Output
100
220
220
280
HINT
1<=N<=100000
Source
首先答案是路径的并的权值和乘2,因为每条边至少需要经过两次(一去一回),而且经过两次必然可以完成遍历。。。
hzwer的做法,答案是dfs序相邻两点距离和加上首尾的距离和,这样保证了每条边都经过了两遍。。。
根据虚树那套理论:
考虑dfs序相邻的两个点x,y和其Lca(dfn[Lca]<=dfn[x]<dfn[y])的关系只有两种情况:
1.x=Lca;
那么y在x的子树内,并且是一棵新的子树,这样x->y的路径被第一次经过。。。
2.x和y分居在Lca的两棵不同子树中,并且我们知道x是Lca的某个子树的叶子节点(即Lca->x的所有路径都被经过了一次),
而y是Lca的一棵新子树,那么从x->y的路径,经过的路径就是从x->Lca的路径第二次被进过而且不会被再次经过。。。
Lca->y的路径被第一次经过。。。最后我们再从dfs序最大的叶子结点回到根节点,保证其路径被经过了两遍。。。
然后我们就只需要用set来维护dfs序相邻两点的距离即可。。。
// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#define int long long
using namespace std;
typedef long long ll;
const int N=300050;
int head[N],to[N],nxt[N],w[N],cnt,n,m,bj[N];
int deep[N],size[N],top[N],dfn[N],id[N],son[N],fa[N],tt;
ll dis[N],ans;
set<ll> s;
set<ll>::iterator it,pre,nex;
void lnk(int x,int y,int z){
to[++cnt]=y,nxt[cnt]=head[x],w[cnt]=z,head[x]=cnt;
to[++cnt]=x,nxt[cnt]=head[y],w[cnt]=z,head[y]=cnt;
}
void dfs1(int x,int f){
size[x]=1;deep[x]=deep[f]+1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];if(y==f) continue;
dis[y]=dis[x]+w[i];dfs1(y,x);
size[y]+=size[x];fa[y]=x;
if(size[y]>size[son[x]]) son[x]=y;
}
}
void dfs2(int x,int f){
top[x]=f;dfn[x]=++tt;id[tt]=x;
if(son[x]) dfs2(son[x],f);
for(int i=head[x];i;i=nxt[i]){
int y=to[i];if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(deep[x]<deep[y]) swap(x,y);
return y;
}
ll calc(int x,int y){return dis[x]+dis[y]-2*dis[lca(x,y)];}
void add(int x){
s.insert(dfn[x]);it=s.find(dfn[x]);
if(it!=s.begin()){pre=it;pre--;}
else {pre=s.end();pre--;}
if((++it)!=s.end()){nex=it;it--;}
else {nex=s.begin();}
ans+=(calc(x,id[*pre])+calc(x,id[*nex])-calc(id[*pre],id[*nex]));
}
void del(int x){
it=s.find(dfn[x]);
if(it!=s.begin()){pre=it;pre--;}
else {pre=s.end();pre--;}
if((++it)!=s.end()){nex=it;it--;}
else {nex=s.begin();}
ans-=(calc(x,id[*pre])+calc(x,id[*nex])-calc(id[*pre],id[*nex]));
s.erase(dfn[x]);
}
main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<n;i++){
int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);
lnk(x,y,z);
}
dfs1(1,0);dfs2(1,1);
for(int i=1;i<=m;i++){
int x;scanf("%d",&x);bj[x]^=1;
if(bj[x]) add(x);else del(x);
printf("%lld\n",ans);
}
return 0;
}
bzoj 3991: [SDOI2015]寻宝游戏的更多相关文章
- bzoj 3991: [SDOI2015]寻宝游戏 虚树 set
目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...
- 树形结构的维护:BZOJ 3991: [SDOI2015]寻宝游戏
Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...
- BZOJ 3991: [SDOI2015]寻宝游戏 树链的并+set
Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...
- [BZOJ 3991][SDOI2015]寻宝游戏(dfs序)
题面 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ...
- BZOJ 3991: [SDOI2015]寻宝游戏 [虚树 树链的并 set]
传送门 题意: $n$个点的树,$m$次变动使得某个点有宝物或没宝物,询问每次变动后集齐所有宝物并返回原点的最小距离 转化成有根树,求树链的并... 两两树链求并就可以,但我们按照$dfs$序来两两求 ...
- BZOJ.3991.[SDOI2015]寻宝游戏(思路 set)
题目链接 从哪个点出发最短路径都是一样的(最后都要回来). 脑补一下,最短路应该是按照DFS的顺序,依次访问.回溯遍历所有点,然后再回到起点. 即按DFS序排序后,Ans=dis(p1,p2)+dis ...
- 3991: [SDOI2015]寻宝游戏
3991: [SDOI2015]寻宝游戏 https://www.lydsy.com/JudgeOnline/problem.php?id=3991 分析: 虚树+set. 要求树上许多点之间的路径的 ...
- 【BZOJ】3991: [SDOI2015]寻宝游戏
题意 给一个\(n\)个点带边权的树.有\(m\)次操作,每一次操作一个点\(x\),如果\(x\)已经出现,则\(x\)消失.否则\(x\)出现.每一操作后,询问从某个点开始走,直到经过所有出现的点 ...
- 【BZOJ】3991: [SDOI2015]寻宝游戏 虚树+DFS序+set
[题意]给定n个点的带边权树,对于树上存在的若干特殊点,要求任选一个点开始将所有特殊点走遍后返回.现在初始没有特殊点,m次操作每次增加或减少一个特殊点,求每次操作后的总代价.n,m<=10^5. ...
随机推荐
- java 之 建造者模式(大话设计模式)
建造者模式,在笔者看来比较试用于,定制一个业务流程,而流程的细节又不尽相同,每个细节又必不可少,这时应考虑使用建造者模式. 大话设计模式-类图 先看下笔者写的一个简单的例子. /** * 所有建造过程 ...
- SaltStack 安装介绍 01
一.入门指南 1.1 SALTSTACK是什么? The backbone of Salt is the remote execution engine, which creates a high-s ...
- Code Kata:大整数比较大小&大整数四则运算---加减法 javascript实现
大整数的四则运算已经是老生常谈的问题了.很多的库也已经包含了各种各样的解决方案. 作为练习,我们从最简单的加减法开始. 加减法的核心思路是用倒序数组来模拟一个大数,然后将两个大数的利用竖式进行运算. ...
- SQL Server学习之路(八):扩展SQL语句
0.目录 1.问题描述 2.第一种方法 通过GROUP BY子句解决 3.第二种方法 通过聚合函数解决 4.第三种方法 在select...from...中的from后面嵌套一个表 5.第四种方法 在 ...
- Redis的简单使用和介绍
1.什么是NoSQL NoSQL = Not Only SQL 非关系型的数据库 2. 为什么需要NoSQL High performance 高并发读写 ...
- NGUI_Input
九.输入框Input 1.凡是用户可以输入文本的地方,几乎都用输入框,有登录账号和密码.输入角色名称.输入聊天内容 2.手动拼接输入框,拖动预制体的就不再说了 (1).创建一个Sprite作为输入框的 ...
- Angular之指令Directive系列
项目筹备近期开启Angular学习,指令比较难理解所以记录备案,推荐Angualr实战学习视频大漠穷秋 Angular实战 一.指令directive概述 指令可以对元素绑定事件监听或者改变DOM结构 ...
- 探索版 webstorm快捷方式
ctrl + alt + s 打开配置面板 Settings 国内的资料比较少,大概很多人已经放弃了原生快捷方式,不过我打算通关原生快捷方式. 在配置面板中 IDE S ...
- 修改Mac系统的文件权限
修改Mac系统的文件权限 有时候,因为各种各样的需求Mac OS系统使用者需要修改某个系统文件,但是很多时候Mac OS系统会提示你"没有足够的权限".所以往往会无法保侟.编辑甚至 ...
- Android从无知到有知——NO.1
如期而至的软件设计大赛吹响了重生的号角.正如同我们的指导老师所说,这个暑假会影响你近几年的发展,也可能会决定你以后所走的道路. 是的.我身边就有非常好的样例,有些师哥师姐们常常跟我们说.软件大赛不仅使 ...