【BZOJ1095】捉迷藏(动态点分治)

题面

BZOJ

题解

动态点分治板子题

假设,不考虑动态点分治

我们来想怎么打暴力:

\(O(n)DP\)求树的最长链

一定都会。不想解释了

所以,利用上面的思想

对于每个点,维护子树到他的最长链

以及子树到他的次长链

把这两个玩意拼起来就可能是答案啦

所以,每个点维护两个堆

一个维护子树上的点到他的距离

一个维护所有子树的前面那个堆的最大值

也就是所以子树中,到达当前点的最长链

再在全局维护一个堆

记录每个点最长链和次长链的和

这样子就可以动态的维护了

但是,因为细节很多

一定要讨论详细

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<set>
  8. #include<map>
  9. #include<vector>
  10. #include<queue>
  11. using namespace std;
  12. #define MAX 120000
  13. inline int read()
  14. {
  15. int x=0,t=1;char ch=getchar();
  16. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  17. if(ch=='-')t=-1,ch=getchar();
  18. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  19. return x*t;
  20. }
  21. int n;
  22. struct Priority_queue
  23. {
  24. priority_queue<int> q,d;
  25. void push(int x){q.push(x);}
  26. void del(int x){d.push(x);}
  27. void pop()
  28. {
  29. while(!d.empty()&&q.top()==d.top())q.pop(),d.pop();
  30. q.pop();
  31. }
  32. int top()
  33. {
  34. while(!d.empty()&&q.top()==d.top())q.pop(),d.pop();
  35. if(q.empty())return 0;
  36. return q.top();
  37. }
  38. int size(){return q.size()-d.size();}
  39. int s_top()
  40. {
  41. if(size()<2)return 0;
  42. int t=top();pop();
  43. int ret=top();push(t);
  44. return ret;
  45. }
  46. }A,B[MAX],C[MAX];
  47. struct Line{int v,next;}e[MAX<<1];
  48. int h[MAX],cnt=1;
  49. inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
  50. /************************************************************************/
  51. int dfn[MAX],top[MAX],dep[MAX],ssize[MAX],hson[MAX],fa[MAX];
  52. void dfs1(int u,int ff)
  53. {
  54. fa[u]=ff;ssize[u]=1;dep[u]=dep[ff]+1;
  55. for(int i=h[u];i;i=e[i].next)
  56. {
  57. int v=e[i].v;
  58. if(v==ff)continue;
  59. dfs1(v,u);
  60. ssize[u]+=ssize[v];
  61. if(ssize[hson[u]]<ssize[v])hson[u]=v;
  62. }
  63. }
  64. void dfs2(int u,int tp)
  65. {
  66. top[u]=tp;
  67. if(hson[u])dfs2(hson[u],tp);
  68. for(int i=h[u];i;i=e[i].next)
  69. {
  70. int v=e[i].v;
  71. if(v==fa[u]||v==hson[u])continue;
  72. dfs2(v,v);
  73. }
  74. }
  75. int LCA(int u,int v)
  76. {
  77. while(top[u]!=top[v])
  78. {
  79. if(dep[top[u]]<dep[top[v]])swap(u,v);
  80. u=fa[top[u]];
  81. }
  82. return dep[u]<dep[v]?u:v;
  83. }
  84. int Dis(int u,int v)
  85. {
  86. return dep[u]+dep[v]-dep[LCA(u,v)]*2;
  87. }
  88. /************************************************************************/
  89. int size[MAX],Fa[MAX];
  90. int cl[MAX],tot,Size,minr;
  91. int root;
  92. bool vis[MAX];
  93. void Getroot(int u,int ff)
  94. {
  95. size[u]=1;
  96. int ret=0;
  97. for(int i=h[u];i;i=e[i].next)
  98. {
  99. int v=e[i].v;
  100. if(v==ff||vis[v])continue;
  101. Getroot(v,u);
  102. size[u]+=size[v];
  103. ret=max(ret,size[v]);
  104. }
  105. ret=max(ret,Size-size[u]);
  106. if(ret<minr)minr=ret,root=u;
  107. }
  108. void Div(int u,int ff)//把树给割开
  109. {
  110. vis[u]=true;Fa[u]=ff;
  111. for(int i=h[u];i;i=e[i].next)
  112. {
  113. int v=e[i].v;
  114. if(v==ff||vis[v])continue;
  115. minr=n;Size=size[v];
  116. Getroot(v,u);
  117. Div(root,u);
  118. }
  119. }
  120. //A:全局用来维护最大距离,存每个B的最大值和次大值之和(也就是拼出的链)
  121. //B:维护所有子树到当前点的最长距离,也就是所有子节点C的top
  122. //C:维护所有子树到当前点的距离
  123. void Turn_Off(int u,int v)//关掉v的灯
  124. {
  125. if(u==v)//如果就是自己这里
  126. {
  127. B[u].push(0);//插一个0进来,自己到自己有长度为0的链
  128. if(B[u].size()==2)A.push(B[u].top());
  129. //如果size超过2,意味着有超过两条链,就可能拼出一个答案
  130. //如果size等于2,有一条链和一条长度为0的链
  131. }
  132. if(!Fa[u])return;//到了顶上了
  133. int ff=Fa[u],D=Dis(ff,v),tmp=C[u].top();
  134. C[u].push(D);//对上一层的贡献
  135. if(D>tmp)//比当前层给的贡献要大一些
  136. {
  137. int mx=B[ff].top()+B[ff].s_top(),sz=B[ff].size();
  138. //mx是去两条链拼出一个可能的答案
  139. if(tmp)B[ff].del(tmp);//上一层的值要被替换掉
  140. B[ff].push(D);//换成一个更大的值
  141. int now=B[ff].top()+B[ff].s_top();//当前的两条最长链
  142. if(now>mx)//比原来的那条链要大一些
  143. {
  144. if(sz>=2)A.del(mx);//如果超过两条链就把原来的答案给删掉
  145. if(B[ff].size()>=2)A.push(now);//换上一个新的答案
  146. }
  147. }
  148. Turn_Off(ff,v);//往上递归
  149. }
  150. void Turn_On(int u,int v)//打开v的灯
  151. {
  152. if(u==v)//如果就是自己这里
  153. {
  154. if(B[u].size()==2)A.del(B[u].top());
  155. B[u].del(0);
  156. }
  157. if(!Fa[u])return;//到了顶上了
  158. int ff=Fa[u],D=Dis(ff,v),tmp=C[u].top();
  159. C[u].del(D);
  160. if(D==tmp)
  161. {
  162. int mx=B[ff].top()+B[ff].s_top(),sz=B[ff].size();
  163. B[ff].del(D);
  164. if(C[u].top())B[ff].push(C[u].top());
  165. int now=B[ff].top()+B[ff].s_top();
  166. if(now<mx)
  167. {
  168. if(sz>=2)A.del(mx);
  169. if(B[ff].size()>=2)A.push(now);
  170. }
  171. }
  172. Turn_On(ff,v);//往上递归
  173. }
  174. /************************************************************************/
  175. int main()
  176. {
  177. n=read();
  178. for(int i=1,a,b;i<n;++i)a=read(),b=read(),Add(a,b),Add(b,a);
  179. dfs1(1,0);dfs2(1,1);
  180. root=0;minr=Size=n;Getroot(1,0);
  181. Div(root,0);
  182. for(int i=1;i<=n;++i)C[i].push(0);
  183. for(int i=1;i<=n;++i)cl[i]=1;//默认关上
  184. for(int i=1;i<=n;++i)Turn_Off(i,i),++tot;
  185. char ch[3];
  186. int Q=read();
  187. while(Q--)
  188. {
  189. scanf("%s",ch);
  190. if(ch[0]=='G')
  191. {
  192. if(tot<=1)printf("%d\n",tot-1);
  193. else printf("%d\n",A.top());
  194. }
  195. else
  196. {
  197. int x=read();
  198. if(cl[x])Turn_On(x,x),tot--;
  199. else Turn_Off(x,x),tot++;
  200. cl[x]^=1;
  201. }
  202. }
  203. return 0;
  204. }

【BZOJ1095】捉迷藏(动态点分治)的更多相关文章

  1. 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

    [BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...

  2. BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...

  3. 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆

    题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...

  4. bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习

    好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...

  5. BZOJ1095:[ZJOI2007]Hide 捉迷藏(动态点分治)

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  6. 【BZOJ1095】【ZJOI2007】捉迷藏 [动态点分治]

    题解: 好像还是比较简单的 对每个重心向下一层重心连边 树高是log的 我们对每一层维护两个信息 1.所有节点到上一层重心的距离 2.所有儿子的1堆的堆顶 另外开个总的堆 维护每一层最长+次长 修改是 ...

  7. 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)

    题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...

  8. bzoj 1095 Hide 捉迷藏 - 动态点分治 -堆

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双 ...

  9. BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治

    [题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...

  10. BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)

    传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...

随机推荐

  1. hbuilder ios 打包失败,无法导入p12证书的解决方案

    问题描述: 在profile文件和私钥证书通过hbuilder ios 打包成功过的前提下,突然遇到打包失败的问题,问题详情是无法导入p12证书. 探索过程: 本着遇到问题先自省的态度,重复打包了几次 ...

  2. 零基础2018如何系统地学习python?

    首先告诉你的是,零基础学习开始系统学习Python肯定难,Python的专业程度本身就不简单,学习这事本来就是一件非常煎熬的事情,人都不愿意学习,可是没办法,为了生存掌握一个技能,你必须学,如果你认真 ...

  3. js小技巧:数组去重

    JavaScript 数组中去除重复的数据 var arr = [1, 2, 2, 3, '1', null, 'a', 'b', 'a']; var t = {}; var result = arr ...

  4. python学习:99乘法口诀

    #!/usr/bin/python   for i in xrange(1,10):     for j in xrange(1,i+1):         print "%s*%s=%s& ...

  5. [HNOI2009] 梦幻布丁

    [HNOI2009] 梦幻布丁 标签: 链表 题解 可以直接用链表启发式合并做. 合并的细节处理稍微有点麻烦. 假如需要变成另一种颜色的那个颜色的个数更多,那么就肯定不能直接合. 维护一个color数 ...

  6. WEB页面的生命周期,DOMContentLoaded,load,beforeunload,unload

    简言 理解WEB页面的生命周期,文档加载事件及顺序对WEB开发有十分的重要意义.如果不理解,在元素未加载就提前操作元素,则得不到想要的结果.而如果页面完全加载完成后,再进行操作,则又会影响用户体验. ...

  7. 跟面向对象卯上了,看看ES6的“类”

    上回我们说到ES5的面向对象,以及被大家公认的最佳的寄生组合式继承.时代在进步,在ES6中对于面向对象这个大boss理所应当地进行了一次大改,从原先那种比较长的写法转变为"小清新" ...

  8. 【Unity3D技术文档翻译】第1.2篇 为打包 AssetBundles 准备资产

    本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced Development]→[AssetBundles]→[Preparing Assets f ...

  9. Java经典编程题50道之二十九

    求一个3*3矩阵对角线元素之和. public class Example29 {    public static void main(String[] args) {        int[][] ...

  10. 一种解决eclipse中安装maven出错的方法

    1.安装步骤:https://jingyan.baidu.com/article/a17d5285feb4dd8099c8f26e.html 2.安装第三步的解决办法:m2e   路径换成  http ...