【BZOJ】3991: [SDOI2015]寻宝游戏
题意
给一个\(n\)个点带边权的树。有\(m\)次操作,每一次操作一个点\(x\),如果\(x\)已经出现,则\(x\)消失。否则\(x\)出现。每一操作后,询问从某个点开始走,直到经过所有出现的点,最后再回到开始的那个点的最短路程。
分析
首先容易知道我们选任意一个在某两点路径上的点作为起点都能得到最优解(包括端点)。我们只需要考虑走的顺序。
题解
由于按照dfs序的走法是最短的,因此我们按dfs序维护一下前前后后的距离和即可。如何证明?好像并不会...
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100005;
int n, ihead[N], FF[N], dep[N], cnt, a[N], fa[N][17], m;
ll d[N];
struct E {
int next, to, w;
}e[N<<1];
struct dat {
int FF, id;
ll dis;
bool operator < (const dat &a) const {
return FF<a.FF;
}
};
set<dat> s;
void add(int x, int y, int w) {
e[++cnt]=(E){ihead[x], y, w}; ihead[x]=cnt;
e[++cnt]=(E){ihead[y], x, w}; ihead[y]=cnt;
}
void dfs(int x, int f=0) {
static int fid=0;
FF[x]=++fid;
for(int i=1; i<=16; ++i) {
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(int i=ihead[x]; i; i=e[i].next) {
int y=e[i].to;
if(y==f) {
continue;
}
fa[y][0]=x;
dep[y]=dep[x]+1;
d[y]=d[x]+e[i].w;
dfs(y, x);
}
}
int LCA(int x, int y) {
if(dep[x]<dep[y]) {
swap(x, y);
}
int d=dep[x]-dep[y];
for(int i=16; i>=0; --i) if((d>>i)&1) x=fa[x][i];
if(x==y) return x;
for(int i=16; i>=0; --i) if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
return fa[x][0];
}
ll getdis(int x, int y) {
int lca=LCA(x, y);
return d[x]+d[y]-(d[lca]<<1);
}
int main() {
scanf("%d%d", &n, &m);
for(int i=1; i<n; ++i) {
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
add(x, y, w);
}
dfs((n+1)>>1);
ll ans=0;
while(m--) {
int p;
scanf("%d", &p);
dat t;
if(a[p]) {
set<dat>::iterator it=s.lower_bound((dat){FF[p], 0, 0}), itp=s.end(), itb=s.end();
itb=it;
++itb;
ans-=it->dis;
if(it!=s.begin()) {
itp=it;
--itp;
}
if(itb!=s.end()) {
ans-=itb->dis;
if(itp==s.end()) {
t=*itb;
t.dis=0;
s.erase(itb);
s.insert(t);
}
else {
t=*itb;
t.dis=getdis(itb->id, itp->id);
ans+=t.dis;
s.erase(itb);
s.insert(t);
}
}
s.erase(it);
a[p]=0;
}
else {
set<dat>::iterator it=s.lower_bound((dat){FF[p], 0, 0}), itp=s.end();
if(it!=s.begin()) {
itp=it;
--itp;
}
if(it!=s.end()) {
if(itp!=s.end()) {
ll dis=getdis(p, itp->id);
s.insert((dat){FF[p], p, dis});
ans+=dis;
}
else {
s.insert((dat){FF[p], p, 0});
}
t=*it;
ans-=t.dis;
t.dis=getdis(p, it->id);
ans+=t.dis;
s.erase(it);
s.insert(t);
}
else {
if(itp==s.end()) {
s.insert((dat){FF[p], p, 0});
}
else {
ll dis=getdis(p, itp->id);
s.insert((dat){FF[p], p, dis});
ans+=dis;
}
}
a[p]=1;
}
ll temp=0;
if(s.size()>=2) {
set<dat>::iterator it=s.end();
--it;
temp=getdis(s.begin()->id, it->id);
}
printf("%lld\n", ans+temp);
}
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]寻宝游戏
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]寻宝游戏 虚树+DFS序+set
[题意]给定n个点的带边权树,对于树上存在的若干特殊点,要求任选一个点开始将所有特殊点走遍后返回.现在初始没有特殊点,m次操作每次增加或减少一个特殊点,求每次操作后的总代价.n,m<=10^5. ...
随机推荐
- 英文写作——冠词的使用(Use 0f Articles)
1.使用'a','an','the'和不使用冠词的基本规则: <1>泛指,不可数名词不能有任何冠词 <2>泛指,可数,复数名词前不能有冠词 <3>泛指,可数,单数名 ...
- [Head First设计模式]生活中学设计模式——迭代器模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- PHP慢脚本日志和Mysql的慢查询日志
1.PHP慢脚本日志 间歇性的502,是后端 PHP-FPM 不可用造成的,间歇性的502一般认为是由于 PHP-FPM 进程重启造成的. 在 PHP-FPM 的子进程数目超过的配置中的数量时候,会出 ...
- 关于session和cookie
一.cookie机制和session机制的区别 **************************************************************************** ...
- [SQL] SQL学习笔记之基础操作
1 SQL介绍 SQL 是用于访问和处理数据库的标准的计算机语言.关于SQL的具体介绍,我们通过回答如下三个问题来进行. SQL 是什么? SQL,指结构化查询语言,全称是 Structured Qu ...
- 新一代记事本“Notepad++”个性化设置备份
Notepad++是一套非常有特色的自由软件的纯文字编辑器(许可证:GPL),有完整的中文化接口及支援多国语言撰写的功能(UTF8 技术).它的功能比 Windows 中的 Notepad(记事簿)强 ...
- URL、URN、URI的区别?
URL.URN.URI区别 既然Web应用程序的文件等资源是放在服务器上,而服务器是因特网(Internet)上的主机,当然必须要有个方法,告诉浏览器到哪里取得文件等资源.通常会听到有人这么说:“你要 ...
- php glob()函数实现目录文件遍历与寻找与模式匹配的文件路径
采用PHP函数glob实现寻找与模式匹配的文件路径,主要讨论glob()函数的作用和用法,利用glob函数读取目录比其它的要快N倍,因为glob函数是内置函数处理起来自然要快. 一,函数原型 arra ...
- vi 常用命令
1.关于退出 :wq! ----强制保存退出 :wq ---- 保存退出 ZZ ---- 作用和:wq一样,(注意Z是大写的,并且不是在命令模式) :q ---- 退出 :q! --- 强 ...
- 非常简单的升级phpnow自带的php版本到5.3的方法
下载PHP5.3 下载地址百度一下“PHP5.3下载”就有很多网站提供下载的,也可以去官网下载最新的,记得下载ZIP压缩的噢 2 解压与命名 将下载的PHP5.3压缩包解压至phpnow的安装目录,命 ...