[SDOI2015]寻宝游戏

题目描述

小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。

小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

4 5

1 2 30

2 3 50

2 4 60

2

3

4

2

1

输出样例#1:

0

100

220

220

280

说明

1<=N<=100000

1<=M<=100000

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

Old Fish 强势秒切 Orz Orz Orz Orz Orz Orz

手动推一下样例或者自己思考一下可以发现,从任意一个点出发都是等效的

\[ans=dist(a1,a2)+dis(a2,a3)+...+dist(ai-1,ai)+dist(ai,a1)
\]

\[1<=i<=m$$**ai按照dfs序从小到大排列**

所以我们可以发现对于每一个点,影响到最终答案的只有它的前趋和后继。所以我们用set维护有宝物的点的dfs序,每次更新答案即可。
```cpp
#include<bits/stdc++.h>
#define lll long long
#define It set<lll>::iterator
using namespace std;
lll read()
{
lll x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
const lll N=100010;
lll n,m,cnt,visnum,ans,x,y,z;
lll head[N],deep[N],dfn[N],pos[N],vis[N],f[N][20],sum[N][20];
set<lll> s;
struct node{
lll v,to,next;
}edge[2*N];
void add(lll x,lll y,lll z)
{
cnt++;edge[cnt].to=y;edge[cnt].v=z;edge[cnt].next=head[x];head[x]=cnt;
}
void dfs(lll k,lll fa)
{
dfn[k]=++visnum;pos[visnum]=k;
for(lll i=head[k];i;i=edge[i].next)
{
lll v=edge[i].to;if(v==fa) continue;
deep[v]=deep[k]+1;f[v][0]=k;sum[v][0]=edge[i].v;dfs(v,k);
}
}
void init()
{
for(lll i=1;i<=19;i++)
for(lll j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1],sum[j][i]=sum[j][i-1]+sum[f[j][i-1]][i-1];
}
lll lca(lll x,lll y)
{
lll qwe=0;
if(deep[x]<deep[y]) swap(x,y);
for(lll i=19;i>=0;i--)
if(deep[f[x][i]]>=deep[y]) qwe+=sum[x][i],x=f[x][i];
if(x==y) return qwe;
for(lll i=19;i>=0;i--)
if(f[x][i]!=f[y][i]) qwe+=sum[x][i]+sum[y][i],x=f[x][i],y=f[y][i];
return qwe+sum[x][0]+sum[y][0];
}
It l(It k)
{
if(k==s.begin()) return --s.end();
return --k;
}
It r(It k)
{
if(k==--s.end()) return s.begin();
return ++k;
}
void change1(lll k)
{
It it;lll t;
if(s.size())
{
it=s.lower_bound(dfn[k]);
if(it==s.end()) it=s.begin();
t=*l(it);
ans+=lca(k,pos[t])+lca(k,pos[*it])-lca(pos[t],pos[*it]);
}
s.insert(dfn[k]);
}
void change2(lll k)
{
It it;lll t;
it=s.find(dfn[k]);
t=*l(it);it=r(it);
ans-=lca(k,pos[t])+lca(k,pos[*it])-lca(pos[t],pos[*it]);
s.erase(dfn[k]);
}
int main()
{
n=read();m=read();
for(lll i=1;i<n;i++)
{
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
dfs(1,0);init();
for(lll i=1;i<=m;i++)
{
x=read();
if(!vis[x]) change1(x),vis[x]=1;
else change2(x),vis[x]=0;
printf("%lld\n",ans);
}
return 0;
}
```\]

[SDOI2015]寻宝游戏(LCA,set)的更多相关文章

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

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

  2. bzoj 3991: [SDOI2015]寻宝游戏 虚树 set

    目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...

  3. P3320 [SDOI2015]寻宝游戏 解题报告

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

  4. 【LG3320】[SDOI2015]寻宝游戏

    [LG3320][SDOI2015]寻宝游戏 题面 洛谷 题解 不需要建虚树的虚树2333... 贪心地想一下,起始节点肯定是在关键点上,访问顺序就是\(dfs\)序. 那么对于每次询问, \[ An ...

  5. 3991: [SDOI2015]寻宝游戏

    3991: [SDOI2015]寻宝游戏 https://www.lydsy.com/JudgeOnline/problem.php?id=3991 分析: 虚树+set. 要求树上许多点之间的路径的 ...

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

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

  7. P3320 [SDOI2015]寻宝游戏

    题目 P3320 [SDOI2015]寻宝游戏 做法 很巧妙的一种思路,懂了之后觉得大水题 首先要知道:在一棵树上标记一些点,然后从任意一点出发,遍历所有的的最小路径为\(dfs\)序从小到大遍历 那 ...

  8. CH#56C 异象石 和 BZOJ3991 [SDOI2015]寻宝游戏

    异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上 ...

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

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

随机推荐

  1. Python学习笔记(三)- SyntaxError: Non-ASCII character '\xe7' in file

    在编辑Python时,当有中文输出或者注释时,出现错误提示:“SyntaxError: Non-ASCII character '\xe7' in file“ 原因:python的默认编码文件是用的A ...

  2. UEFI手札

    基于Intel TianoCore衍生的EDK-II诞生的UEFI,用来取代Legacy BIOS. INF文件 Module Information File,模块描述文件.Module可以是可执行 ...

  3. p5349 幂

    分析 https://www.cnblogs.com/cjyyb/p/10822490.html 代码 #include<bits/stdc++.h> using namespace st ...

  4. qbzt day2 晚上(竟然还有晚上)

    内容提要 搜索 拓展欧几里得 逆元 先是搜索 A* 有几个数组 g 当前点到根节点的深度 h 当前点到终点理想的最优情况需要走几步 f  f=g+h A*就是把所有的f从小到大排序 启发式搜索相较于其 ...

  5. 建立起BI的支撑团队

    Bobby Luo 罗如意(18907295660@189.cn) 2011年7月 http://weibo.com/cquptvlry 电子商务中的BI应用初探 系统架构 对整个数据仓库的架构进行规 ...

  6. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_05 IO字符流_4字符输出流的基本使用_写出单个字符

    写完之后不刷新,则没有数据.数据只是写如到了内存缓冲区中 必须要调用flush方法,把数据刷新过去 close关闭的时候也会把数据刷新到文件中.这里把flush注释了也是可以的

  7. 封装好日志的类 logging

    import logging from logging import handlers class MyLogger(): def __init__(self,file_name,level='inf ...

  8. c# 解决Socket问题——由于目标机器积极拒绝,无法连接

    关于单机出现这种问题不多赘述,主要阐述服务机和客户机出现这种问题的解决办法. 1.检查防火墙 这种问题出现的最多,特别是你的服务机还是买的各家的云产品,比如阿里云就是到防火墙中添加出入站规则,Azur ...

  9. php-fpm启动不起来,php-fpm无法启动的一种情况

    今天碰了一个很奇怪的问题,平时好好的php-fpm修改了一个参数后,突然启动不起来了,试着把参数还原.甚至用备份的配置文件还原都没办法启动php,而且不给任务启动错误的提示,纳闷!!!后来上网找了个资 ...

  10. Java{0}占位符替换字符串

    Java{0}占位符替换字符串 public class Test { public static void main(String[] args) { System.out.println(Stri ...