【BZOJ3991】[SDOI2015]寻宝游戏

Description

小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物

Input

第一行,两个整数N、M,其中M为宝物的变动次数。

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

Output

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

Sample Input

4 5
1 2 30
2 3 50
2 4 60
2
3
4
2
1

Sample Output

0
100
220
220
280

HINT

1<=N<=100000

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

题解:从前有一个神奇的序列,它叫DFS序,它有一个神奇的性质,就是两点间LCA的深度=两点在DFS序上的区间中深度的最小值。从前有一堆树链,它们跑到了DFS序上,并按DFS序排成了一列,它们的并就是每个树链的长度-相邻两个树链的LCA到根的路径的长度。

这个性质其实很好理解,也很好证吧~

所以我们用set维护DFS序,每加入一个点就找出它在DFS序上的前驱后继,计算树链的并的变化长度,删除时类似。不过由于可以从任意一个节点出发,所以总长度应该减去所有点的LCA到根的路径长度(也就是DFS序最小的和最大的点的LCA),答案就是总长度*2

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <set>
  5. using namespace std;
  6. const int maxn=100010;
  7. typedef long long ll;
  8. ll sum;
  9. int n,m,lgn,cnt,tot;
  10. int to[maxn<<1],next[maxn<<1],head[maxn],fa[maxn][20],p[maxn],q[maxn],dep[maxn],ins[maxn];
  11. set<int> s;
  12. set<int>::iterator it;
  13. ll val[maxn<<1],len[maxn];
  14. int rd()
  15. {
  16. int ret=0,f=1; char gc=getchar();
  17. while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
  18. while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
  19. return ret*f;
  20. }
  21. void add(int a,int b,int c)
  22. {
  23. to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
  24. }
  25. void dfs(int x)
  26. {
  27. q[++p[0]]=x,p[x]=p[0];
  28. for(int i=head[x];i!=-1;i=next[i])
  29. if(to[i]!=fa[x][0])
  30. fa[to[i]][0]=x,len[to[i]]=len[x]+val[i],dep[to[i]]=dep[x]+1,dfs(to[i]);
  31. }
  32. int lca(int a,int b)
  33. {
  34. if(dep[a]<dep[b]) swap(a,b);
  35. int i;
  36. for(i=lgn;i>=0;i--) if(dep[fa[a][i]]>=dep[b]) a=fa[a][i];
  37. if(a==b) return a;
  38. for(i=lgn;i>=0;i--) if(fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
  39. return fa[a][0];
  40. }
  41. int main()
  42. {
  43. n=rd(),m=rd();
  44. int i,j,a,b,c;
  45. memset(head,-1,sizeof(head));
  46. for(i=1;i<n;i++) a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
  47. dep[1]=1,dfs(1);
  48. for(j=1;(1<<j)<=n;j++)
  49. for(lgn=j,i=1;i<=n;i++)
  50. fa[i][j]=fa[fa[i][j-1]][j-1];
  51. for(i=1;i<=m;i++)
  52. {
  53. a=rd();
  54. if(!ins[a])
  55. {
  56. it=s.upper_bound(p[a]),b=c=0;
  57. if(it!=s.end()) c=q[*it];
  58. if(it!=s.begin()) it--,b=q[*it];
  59. if(b&&c) sum+=len[lca(b,c)];
  60. if(b) sum-=len[lca(a,b)];
  61. if(c) sum-=len[lca(a,c)];
  62. tot++,ins[a]=1,sum+=len[a],s.insert(p[a]);
  63. }
  64. else
  65. {
  66. s.erase(p[a]),it=s.upper_bound(p[a]),b=c=0;
  67. if(it!=s.end()) c=q[*it];
  68. if(it!=s.begin()) it--,b=q[*it];
  69. if(b&&c) sum-=len[lca(b,c)];
  70. if(b) sum+=len[lca(a,b)];
  71. if(c) sum+=len[lca(a,c)];
  72. tot--,ins[a]=0,sum-=len[a];
  73. }
  74. if(tot==1||tot==0)
  75. {
  76. printf("0\n");
  77. continue;
  78. }
  79. it=s.begin(),b=q[*it],it=s.end(),--it,c=q[*it];
  80. printf("%lld\n",2*(sum-len[lca(b,c)]));
  81. }
  82. return 0;
  83. }

【BZOJ3991】[SDOI2015]寻宝游戏 树链的并+set的更多相关文章

  1. bzoj3991 [SDOI2015]寻宝游戏 树链的并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3991 题解 貌似这个东西叫做树链的并,以前貌似写过一个类似的用来动态维护虚树. 大概就是最终的 ...

  2. 【bzoj3991】[SDOI2015]寻宝游戏 树链的并+STL-set

    题目描述 给出一棵树,初始每个点都是非必经的.多次改变某个点的必经状态,并询问从任意一个点出发,经过所有必经的点并回到该点的最小路程. 输入 第一行,两个整数N.M,其中M为宝物的变动次数. 接下来的 ...

  3. BZOJ 3991: [SDOI2015]寻宝游戏 树链的并+set

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

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

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

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

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

  6. [bzoj3991][SDOI2015]寻宝游戏_树链的并_倍增lca_平衡树set

    寻宝游戏 bzoj-3991 SDOI-2015 题目大意:题目链接. 注释:略. 想法:我们发现如果给定了一些点有宝物的话那么答案就是树链的并. 树链的并的求法就是把所有点按照$dfs$序排序然后相 ...

  7. bzoj3991 [Sdoi2015]寻宝游戏 set动态维护虚树+树链求并

    题目大意:支持多次操作,增加或删除一个关键点 动态维护虚树边权和*2 分析:可以用树链求并的方法,最后减去虚树的根到1距离 注意到树链求并是所有点到根距离-所有dfn序相邻两点的LCA到根距离 找df ...

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

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

  9. 【dfs序】【set】bzoj3991 [Sdoi2015]寻宝游戏

    在考试代码的基础上稍微改改就a了……当时为什么不稍微多想想…… 插入/删除一个新节点时就把其dfn插入set/从set中删除. 当前的答案就是dfn上相邻的两两节点的距离和,再加上首尾节点的距离. 比 ...

随机推荐

  1. 一个人的安全部之ELK接收Paloalto日志并用钉钉告警

    起因 通报漏洞后,开发未能及时修复漏洞,导致被攻击,领导说我发现被攻击的时间晚了,由于一个人安全部精力有限未能及时看IPS告警,于是做了个钉钉告警. 本人环境介绍 ubuntu 14.04 pytho ...

  2. Linux内核实践之工作队列

    工作队列(work queue)是另外一种将工作推后执行的形式,它和tasklet有所不同.工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行.这样,通过工作 ...

  3. hive数据类型转换、字符串函数、条件判断

    http://blog.csdn.net/yimingsilence/article/details/70057638 数据类型转换 同Java语言一样,Hive也包括 隐式转换(implicit c ...

  4. eclipse自动添加作者、日期等注释

    使用eclipse的时候一般会添加自己的注释,标注日期作者等内容,我总结的添加注释的方式有两种:一.在新建class时自动添加注释:二.通过快捷键自动添加注释.下面分别描述一下添加方式. 一.新建cl ...

  5. call、aply、bind的常用方法总结

    类函数变为数组 function aaa (){ Array.prototype.slice(arguments); } 进一步操作它的每个元素 function bbb() { Array.prot ...

  6. 内网IPC$种马的三种方法

    copy muma.exe \\host\c$\windows\temp\foobar.exe ##IPC拷贝木马文件 WMIC远程运行命令 wmic /node:host /user:adminis ...

  7. C++ 大规模数据排序(100G数据 使用 4G 内存 排序)

    思路很简单,先分段排序,存储到临时文件中,然后合并. 使用10000个整数来模拟大数据,每次读取100个到内存中. #include <stdint.h> #include <std ...

  8. win8硬盘安装Ubuntu14.04双系统參考教程

    硬盘安装,无需光盘.U盘.win8为主.Ubuntu14.04为辅.可将Windows或Ubuntu设置为开机默认启动项.在Ubuntu下可查看.操作Windows系统下的文件:适用于安装和14.04 ...

  9. datatables插件适用示例

    本文共四部分:官网 | 基本使用|遇到的问题|属性表 一:官方网站:[http://www.datatables.NET/] 二:基本使用:[http://www.guoxk.com/node/jQu ...

  10. sort-colors——排序3种数字

    题目描述 Given an array with n objects colored red, white or blue, sort them so that objects of the same ...