问题描述

小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。

样例输入

4 5

1 2 30

2 3 50

2 4 60

2

3

4

2

1

样例输出

0

100

220

220

280

解析

手动模拟之后我们可以发现,对于一个已经确定哪些地方有宝藏的地图,无论从哪个地方出发的路径长度是一样的。稍加归纳我们可以发现,要求的答案就是

\[dis(p_1,p_2)+dis(p_2,p_3)+...+dis(p_{n-1},p_n)
\]

其中\(p\)是按照DFS序排序后的宝藏地点数组。因此,我们可以用set维护所有有宝藏的地点序列,关键字为DFS序。每次插入都找到插入点在set中的前驱后继,然后用LCA求路径长度修改答案即可。

代码

#include <iostream>
#include <cstdio>
#include <set>
#include <cmath>
#define int long long
#define N 100002
using namespace std;
int head[N],ver[N*2],nxt[N*2],edge[N*2],l;
int n,m,i,f[N][20],dep[N],dfn[N],dis[N],tim;
bool vis[N];
struct node{
int p;
node(int _p){p=_p;}
bool operator < (const node &a) const{
return dfn[a.p]<dfn[p];
}
};
set<node> s;
set<node>::iterator it1,it2;
int read()
{
char c=getchar();
int w=0;
while(c<'0'||c>'9') c=getchar();
while(c<='9'&&c>='0'){
w=w*10+c-'0';
c=getchar();
}
return w;
}
void insert(int x,int y,int z)
{
l++;
ver[l]=y;
edge[l]=z;
nxt[l]=head[x];
head[x]=l;
}
void dfs(int x,int pre)
{
dfn[x]=++tim;
f[x][0]=pre;
dep[x]=dep[pre]+1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=pre){
dis[y]=dis[x]+edge[i];
dfs(y,x);
}
}
}
void init()
{
dfs(1,0);
for(int j=0;(1<<(j+1))<=n;j++){
for(int i=1;i<=n;i++) f[i][j+1]=f[f[i][j]][j];
}
}
int LCA(int u,int v)
{
if(dep[u]>dep[v]) swap(u,v);
int tmp=dep[v]-dep[u];
for(int i=0;(1<<i)<=tmp;i++){
if((1<<i)&tmp) v=f[v][i];
}
if(u==v) return u;
for(int i=log2(1.0*n);i>=0;i--){
if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
}
return f[u][0];
}
int dist(int x,int y)
{
return dis[x]+dis[y]-2*dis[LCA(x,y)];
}
signed main()
{
n=read();m=read();
for(i=1;i<n;i++){
int u=read(),v=read(),w=read();
insert(u,v,w);
insert(v,u,w);
}
init();
int ans=0;
for(i=1;i<=m;i++){
int x=read();
if(vis[x]){
vis[x]=0;
if(s.size()!=1){
it1=it2=s.find(node(x));
if(it1==s.begin()) it1=s.end();
it1--;it2++;
if(it2==s.end()) it2=s.begin();
ans+=dist((*it1).p,(*it2).p)-dist(x,(*it1).p)-dist(x,(*it2).p);
}
s.erase(node(x));
}
else{
vis[x]=1;
s.insert(node(x));
if(s.size()!=1){
it1=it2=s.find(node(x));
if(it1==s.begin()) it1=s.end();
it1--;it2++;
if(it2==s.end()) it2=s.begin();
ans-=dist((*it1).p,(*it2).p)-dist(x,(*it1).p)-dist(x,(*it2).p);
}
}
printf("%lld\n",ans);
}
return 0;
}

[洛谷P3320] SDOI2015 寻宝游戏的更多相关文章

  1. [bzoj3991] [洛谷P3320] [SDOI2015] 寻宝游戏

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

  2. 洛谷 P3320 [SDOI2015]寻宝游戏

    因为寻宝路径是一个环,所以寻宝花费的最小时间与起点无关.宝应当按照所有宝藏所在位置的 dfs 序进行才能够使得花费的时间最短.设 \(dist_i\) 表示 \(i\) 到树根的最短距离,那么树上任意 ...

  3. 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)

    被\(STL\)坑害了一个晚上,真的菜的没救了啊. 准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\) 有一个非常重要的性质 在反向迭代器中,+ ...

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

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

  5. P3320 [SDOI2015]寻宝游戏

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

  6. Luogu P3320 [SDOI2015]寻宝游戏 / 异象石 【LCA/set】

    期末考试结束祭! 在期末考试前最后一发的测试中,异象石作为第二道题目出现QAQ.虽然知道是LCA图论,但还是敲不出来QAQ. 花了两天竞赛课的时间搞懂(逃 异象石(stone.pas/c/cpp)题目 ...

  7. luogu P3320 [SDOI2015]寻宝游戏

    大意:给定树, 要求维护一个集合, 支持增删点, 询问从集合中任取一点作为起点, 遍历完其他点后原路返回的最短长度. 集合中的点按$dfs$序排列后, 最短距离就为$dis(s_1,s_2)+...+ ...

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

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

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

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

随机推荐

  1. 【SVN】更新提交失败---- Previous operation has not finished; run 'cleanup' if it was interrupted解决方法

     Previous operation has not finished; run 'cleanup' if it was interrupted 问题出处 解决方法 2017-11-01   08: ...

  2. CSS元素隐藏

    { display: none; /* 不占据空间,无法点击 */ } /*************************************************************** ...

  3. LeetCode.1037-有效的回旋镖(Valid Boomerang)

    这是小川的第387次更新,第416篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第248题(顺位题号是1037).回旋镖是一组各不相同且不在一条直线上的三个点.给出三个点 ...

  4. git上传项目到github教程

    1 本地下载git 2 进到你项目所在地 3 git init(初始化git仓) 4 git add .(git add <file>将文件添加到git) 5 git commit -m ...

  5. Linux c实现一个tcp文件服务器和客户端

    总体需求:编写tcp文件服务器和客户端.客户端可以上传和下载文件. ================================================ 分解需求 客户端功能描述: 1)要 ...

  6. centos7部署rabbitMq

    目录 一.消息中间件相关知识... 1 1.概述... 1 2.消息中间件的组成... 1 3 消息中间件模式分类... 2 4 消息中间件的优势... 3 5 消息中间件应用场景... 4 6 消息 ...

  7. SpringMvc 整合mybatis项目搭建

    1.使用idea创建maven项目 2.在项目src目录下 添加java文件夹 并设置类型为sources,添加resource文件夹 设置为resources 4.修改pom文件 添加引用 < ...

  8. idea运行时 Process finished with exit code -1073741819 (0xC0000005)

    问题描述:        idea中启动项目报   Process finished with exit code -1073741819 (0xC0000005) ,如图所示: 问题解决:      ...

  9. 死磕并发之CountDownLatch解析

    CountDownLatch解析 CountDownLatch是什么 CountDownLatch是基于AQS的阻塞工具,阻塞一个或者多个线程,直到所有的线程都执行完成. CountDownLatch ...

  10. Mac上安装配置Go语言,其实很简单(一)

    下载Go语言可以去:Go语言中文网 安装及自己选择是否修改GOPATH 下载下来后双击安装就好,使用 go version 查看安装版本: 在Mac上安装完成后,会自动设置一些环境变量,使用 go e ...