【BZOJ3991】[SDOI2015]寻宝游戏 树链的并+set
【BZOJ3991】[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
题解:从前有一个神奇的序列,它叫DFS序,它有一个神奇的性质,就是两点间LCA的深度=两点在DFS序上的区间中深度的最小值。从前有一堆树链,它们跑到了DFS序上,并按DFS序排成了一列,它们的并就是每个树链的长度-相邻两个树链的LCA到根的路径的长度。
这个性质其实很好理解,也很好证吧~
所以我们用set维护DFS序,每加入一个点就找出它在DFS序上的前驱后继,计算树链的并的变化长度,删除时类似。不过由于可以从任意一个节点出发,所以总长度应该减去所有点的LCA到根的路径长度(也就是DFS序最小的和最大的点的LCA),答案就是总长度*2
#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
using namespace std;
const int maxn=100010;
typedef long long ll;
ll sum;
int n,m,lgn,cnt,tot;
int to[maxn<<1],next[maxn<<1],head[maxn],fa[maxn][20],p[maxn],q[maxn],dep[maxn],ins[maxn];
set<int> s;
set<int>::iterator it;
ll val[maxn<<1],len[maxn];
int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x)
{
q[++p[0]]=x,p[x]=p[0];
for(int i=head[x];i!=-1;i=next[i])
if(to[i]!=fa[x][0])
fa[to[i]][0]=x,len[to[i]]=len[x]+val[i],dep[to[i]]=dep[x]+1,dfs(to[i]);
}
int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
int i;
for(i=lgn;i>=0;i--) if(dep[fa[a][i]]>=dep[b]) a=fa[a][i];
if(a==b) return a;
for(i=lgn;i>=0;i--) if(fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
int main()
{
n=rd(),m=rd();
int i,j,a,b,c;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
dep[1]=1,dfs(1);
for(j=1;(1<<j)<=n;j++)
for(lgn=j,i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(i=1;i<=m;i++)
{
a=rd();
if(!ins[a])
{
it=s.upper_bound(p[a]),b=c=0;
if(it!=s.end()) c=q[*it];
if(it!=s.begin()) it--,b=q[*it];
if(b&&c) sum+=len[lca(b,c)];
if(b) sum-=len[lca(a,b)];
if(c) sum-=len[lca(a,c)];
tot++,ins[a]=1,sum+=len[a],s.insert(p[a]);
}
else
{
s.erase(p[a]),it=s.upper_bound(p[a]),b=c=0;
if(it!=s.end()) c=q[*it];
if(it!=s.begin()) it--,b=q[*it];
if(b&&c) sum-=len[lca(b,c)];
if(b) sum+=len[lca(a,b)];
if(c) sum+=len[lca(a,c)];
tot--,ins[a]=0,sum-=len[a];
}
if(tot==1||tot==0)
{
printf("0\n");
continue;
}
it=s.begin(),b=q[*it],it=s.end(),--it,c=q[*it];
printf("%lld\n",2*(sum-len[lca(b,c)]));
}
return 0;
}
【BZOJ3991】[SDOI2015]寻宝游戏 树链的并+set的更多相关文章
- bzoj3991 [SDOI2015]寻宝游戏 树链的并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3991 题解 貌似这个东西叫做树链的并,以前貌似写过一个类似的用来动态维护虚树. 大概就是最终的 ...
- 【bzoj3991】[SDOI2015]寻宝游戏 树链的并+STL-set
题目描述 给出一棵树,初始每个点都是非必经的.多次改变某个点的必经状态,并询问从任意一个点出发,经过所有必经的点并回到该点的最小路程. 输入 第一行,两个整数N.M,其中M为宝物的变动次数. 接下来的 ...
- BZOJ 3991: [SDOI2015]寻宝游戏 树链的并+set
Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...
- [BZOJ3991][SDOI2015]寻宝游戏
[BZOJ3991][SDOI2015]寻宝游戏 试题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择 ...
- CH#56C 异象石 和 BZOJ3991 [SDOI2015]寻宝游戏
异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上 ...
- [bzoj3991][SDOI2015]寻宝游戏_树链的并_倍增lca_平衡树set
寻宝游戏 bzoj-3991 SDOI-2015 题目大意:题目链接. 注释:略. 想法:我们发现如果给定了一些点有宝物的话那么答案就是树链的并. 树链的并的求法就是把所有点按照$dfs$序排序然后相 ...
- bzoj3991 [Sdoi2015]寻宝游戏 set动态维护虚树+树链求并
题目大意:支持多次操作,增加或删除一个关键点 动态维护虚树边权和*2 分析:可以用树链求并的方法,最后减去虚树的根到1距离 注意到树链求并是所有点到根距离-所有dfn序相邻两点的LCA到根距离 找df ...
- BZOJ3991 [SDOI2015]寻宝游戏 【dfs序 + lca + STL】
题目 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ...
- 【dfs序】【set】bzoj3991 [Sdoi2015]寻宝游戏
在考试代码的基础上稍微改改就a了……当时为什么不稍微多想想…… 插入/删除一个新节点时就把其dfn插入set/从set中删除. 当前的答案就是dfn上相邻的两两节点的距离和,再加上首尾节点的距离. 比 ...
随机推荐
- 图文介绍openLDAP在windows上的安装配置
目录 概述 测试环境 安装过程 配置启动 客户端介绍 多级DC的ldif文件的配置 [一].概述 什么叫LDAP呢,概念的东西这里就不多讲了,网上搜索下有很多,本文的重点是介绍如何在windows平台 ...
- ES6里关于字符串的拓展
一.子串识别 自从 JS 引入了 indexOf() 方法,开发者们就使用它来识别字符串是否存在于其它字符串中.ES6 包含了以下三个方法来满足这类需求: 1.includes():该方法在给定文本存 ...
- component-scan和annotation-driven
<context:component-scan/> 该xml配置作用是启动Spring的组件扫描功能,自动扫描base-package指定的包及其子文件下的java文件,如果扫描到有@co ...
- 2017.5.9 java多线程总结
参考来自:http://www.cnblogs.com/lwbqqyumidi/p/3804883.html http://blog.csdn.net/gf771115/article/details ...
- 将 xml 文件 转为 DataTable
private static DataTable CreateDataTable(string table) { DataSet dataSet = new DataSet(); string dat ...
- cocos2d-x ios游戏开发初认识(六) 渲染的优化
做程序开发肯定要考虑到内存的优化,毕竟iphone本身的内存就不是非常大.这一节主要说这个cocos2d开发对内存的优化,详细表如今,既能够对同样的精灵(图片)仅仅渲染一次,也能够对不能的精灵仅仅渲染 ...
- EffectiveJava(6)消除过期对象的引用
消除过期对象的引用 过期引用 – 在操作集合类的时候,未清理过期的对象引用(即:过期引用),常会导致内存泄露.从而报outOfmemory错误. 1.过期对象导致内存泄漏. 2.一旦对象引用过期,清除 ...
- 倒计时:CountDownLatch(火箭发射前的准备)读书笔记
这是一个非常实用的多线程控制工具类,经典的场景就是 火箭发射,在火箭发射前,为了保证万无一失,往往还要进行各项设备,仪器的检查,只有等待所有的检查完毕后,引擎才能点火, CountDown ...
- MySQL高可用解决方案MMM
一.MMM简介: MMM即Multi-Master Replication Manager for MySQL:mysql多主复制管理器,基于perl实现,关于mysql主主复制配置的监控.故障转移和 ...
- 利用gearman同步mysql数据到redis
一.Gearman 1.Gearman是一个分发任务的程序框架. 2.体系:a.client:发送一个jobb.server:找到合适的worker,把job交给该workerc.worker:处理j ...