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. ...
随机推荐
- Windows下安装BeautifulSoup
python版本为2.7 1.去官网下载BeautifulSoup4 Beautiful Soup 4.3.2 2.解压文件 将下载得到的压缩包解压到任意文件夹,路径不含中文 3.打开cmd命令提示符 ...
- 将百度的ECharts整合到阿里的Weex中。
由于公司的业务,之前PC版产品中,大量的使用了百度的ECharts库.所以现在要做移动端,在大概熟悉了Weex基本语法和搭建环境后,就着手研究如何将这两个好东西糅合起来. 首先,按照Weex官方教程, ...
- Mybatis(三)返回值
Mybatis返回值 MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType是直接表示返回类型的,而resultMap则 ...
- python 小白(无编程基础,无计算机基础)的开发之路,辅助知识6 python字符串/元组/列表/字典互转
神奇的相互转换,小白同学可以看看,很有帮助 #1.字典dict = {'name': 'Zara', 'age': 7, 'class': 'First'} #字典转为字符串,返回:<type ...
- 使用fastdfs-zyc监控FastDFS文件系统
1.安装jdk运行环境 jdk下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html 此处我使用的jdk7U99 ...
- 小白的Python之路 day1 Python3的bytes/str之别
原文:The bytes/str dichotomy in Python 3 Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分.文本总是Unicode,由str类型表示,二 ...
- Solr7使用Oracle数据源导入+中文分词
安装目录假设为#solr_home,本文的#solr_home为apps/svr/solr 1. 在#solr_home/server/solr下新建文件夹,假设为mjd 2. 将#solr_home ...
- Linux----CentOS-7搭建免流服务器
本次实验采用腾讯云服务器:https://cloud.tencent.com/ 大学生身份的可以看看有没有什么活动购买 其他身份的78一个月 关于腾讯云服务器的使用可以看看腾讯云的使用手册 本博客涉及 ...
- LeetCode139:Word Break
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separa ...
- springboot定时任务——整合Quartz
http://blog.csdn.net/liuchuanhong1/article/details/60873295 http://blog.csdn.net/lyg_come_on/article ...