原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html

题目传送门 - BZOJ1095

题意

  有 N 个点,每一个点是黑色或者白色,一开始所有点的颜色都是黑色。有 M 次操作,每次操作有两种类型:1. 修改一个点的颜色;2. 查询树上所有黑色点对之间的距离最大值。

  $N\leq 100000,m\leq 500000$

题解

  写个动态点分治。

  对于一个点分中心,维护两个可删堆:

  1. 维护一下当前连通块的所有黑点到 当前点分中心在点分树上的父亲节点 之间的距离。

  2. 维护一下当前点分中心所有子树的最深深度,这个东西显然可以通过子树中维护的 1. 来得到。

  对于全局,维护一个可删堆,把每一个节点的 2 号堆中最大两个值的和扔进去。

  这个可删堆有一种方便的写法,见代码。

  每次修改直接暴力上跳。注意堆中元素个数不足的情况。

  求 LCA 最好写欧拉序 + 倍增。不然,虽然能在 BZOJ 通过,但是会在一个测试点 5s 的情况下被卡常。

代码

  1. #pragma GCC optimize("O2")
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. const int N=100005;
  5. int read(){
  6. int x=0;
  7. char ch=getchar();
  8. while (!isdigit(ch))
  9. ch=getchar();
  10. while (isdigit(ch))
  11. x=(x<<1)+(x<<3)+ch-48,ch=getchar();
  12. return x;
  13. }
  14. struct AB_Heap{
  15. priority_queue <int> A,B;
  16. int sz;
  17. void clear(){
  18. while (!A.empty())
  19. A.pop();
  20. while (!B.empty())
  21. B.pop();
  22. sz=0;
  23. }
  24. int size(){return sz;}
  25. void push(int x){A.push(x),sz++;}
  26. void pop(int x){B.push(x),sz--;}
  27. int top(){
  28. while (!B.empty()&&A.top()==B.top())
  29. A.pop(),B.pop();
  30. return A.top();
  31. }
  32. int top2(){
  33. int x=top(),y;
  34. pop(x),y=top(),push(x);
  35. return x+y;
  36. }
  37. }S[N],SF[N],ans;
  38. int n,m,tot;
  39. int depth[N],in[N],out[N],eu[N*2],ST[N*2][20],Log[N*2];
  40. int Dfa[N],vis[N],Time=0,size[N],Max[N],now[N];
  41. vector <int> e[N];
  42. void dfs1(int x,int pre,int d){
  43. depth[x]=d,eu[in[x]=++Time]=x;
  44. for (vector <int> :: iterator y=e[x].begin();y!=e[x].end();y++)
  45. if ((*y)!=pre)
  46. dfs1(*y,x,d+1),eu[++Time]=x;
  47. out[x]=Time;
  48. }
  49. void Get_ST(int n){
  50. Log[1]=0;
  51. for (int i=2;i<=n;i++)
  52. Log[i]=Log[i>>1]+1;
  53. for (int i=1;i<=n;i++){
  54. ST[i][0]=eu[i];
  55. for (int j=1;j<20;j++){
  56. ST[i][j]=ST[i][j-1];
  57. int p=i-(1<<(j-1));
  58. if (p>0&&depth[ST[p][j-1]]<depth[ST[i][j]])
  59. ST[i][j]=ST[p][j-1];
  60. }
  61. }
  62. }
  63. int LCA(int x,int y){
  64. if (in[x]>out[y])
  65. swap(x,y);
  66. int L=in[x],R=out[y],d=Log[R-L+1];
  67. int a=ST[L+(1<<d)-1][d],b=ST[R][d];
  68. return depth[a]<depth[b]?a:b;
  69. }
  70. int Distance(int x,int y){
  71. return depth[x]+depth[y]-2*depth[LCA(x,y)];
  72. }
  73. int Node[N],Node_cnt=0;
  74. void dfs2(int x,int pre){
  75. if (vis[x]>=Time){
  76. size[x]=0;
  77. return;
  78. }
  79. size[x]=1,vis[x]=Time,Max[x]=0;
  80. Node[++Node_cnt]=x;
  81. for (vector <int> :: iterator y=e[x].begin();y!=e[x].end();y++){
  82. if ((*y)==pre)
  83. continue;
  84. dfs2(*y,x);
  85. size[x]+=size[*y];
  86. Max[x]=max(Max[x],size[*y]);
  87. }
  88. }
  89. int build(int x,int pre){
  90. Time++,Node_cnt=0,dfs2(x,0);
  91. int mi=x,v=Max[x];
  92. for (int i=1;i<=Node_cnt;i++){
  93. int y=Node[i],vy=max(Max[y],size[x]-size[y]);
  94. if (vy<v)
  95. v=vy,mi=y;
  96. }
  97. Dfa[x=mi]=pre,vis[x]=1e9,SF[x].clear();
  98. for (int i=1;i<=Node_cnt;i++)
  99. SF[x].push(Distance(pre,Node[i]));
  100. S[x].clear(),S[x].push(0);
  101. for (vector <int> :: iterator y=e[x].begin();y!=e[x].end();y++)
  102. if (vis[*y]<1e9)
  103. S[x].push(SF[build(*y,x)].top());
  104. if (S[x].size()>=2)
  105. ans.push(S[x].top2());
  106. return x;
  107. }
  108. void update(int x){
  109. if (S[x].size()>=2) ans.pop(S[x].top2());
  110. if (now[x])
  111. S[x].push(0);
  112. else
  113. S[x].pop(0);
  114. if (S[x].size()>=2) ans.push(S[x].top2());
  115. for (int y=x;Dfa[y];y=Dfa[y]){
  116. int z=Dfa[y],d=Distance(x,z);
  117. if (SF[y].size()&&SF[y].top()>d)
  118. if (now[x])
  119. SF[y].push(d);
  120. else
  121. SF[y].pop(d);
  122. else {
  123. if (S[z].size()>=2) ans.pop(S[z].top2());
  124. if (SF[y].size()) S[z].pop(SF[y].top());
  125. if (now[x])
  126. SF[y].push(d);
  127. else
  128. SF[y].pop(d);
  129. if (SF[y].size()) S[z].push(SF[y].top());
  130. if (S[z].size()>=2) ans.push(S[z].top2());
  131. }
  132. }
  133. tot+=now[x]?1:-1,now[x]^=1;
  134. }
  135. int main(){
  136. tot=n=read();
  137. for (int i=1;i<n;i++){
  138. int a=read(),b=read();
  139. e[a].push_back(b);
  140. e[b].push_back(a);
  141. }
  142. dfs1(1,0,0),Get_ST(n*2-1);
  143. ans.clear(),build(1,0);
  144. m=read();
  145. while (m--){
  146. char ch[10];
  147. scanf("%s",ch);
  148. if (ch[0]=='C')
  149. update(read());
  150. else
  151. printf("%d\n",tot<=1?tot-1:ans.top());
  152. }
  153. return 0;
  154. }

  

BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆的更多相关文章

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

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

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

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

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

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

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

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

  5. BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆

    写了7k多,可以说是一己之力切掉了这道毒瘤题~ 开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ...

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

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

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

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

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

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

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

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

随机推荐

  1. django-form介绍

    Django form表单   目录 普通方式手写注册功能 views.py login.html 使用form组件实现注册功能 views.py login2.html 常用字段与插件 initia ...

  2. PHP中get请求中参数的key不能是para

    &para会被转化成¶,然后就无法进行下去了. 仅作记录.

  3. [MySql]索引的一些技巧

    一.多表子从查询 多表查询时,子查询可能会出现触发不了索引的情况 ,)); 上面语句,test_1和test_public都WHERE了主键id,常理来说这个查询不存在问题,事实上主语句并不会触发索引 ...

  4. linux学习之软件包安装

    本学习基于redhat系统或者centos系统 一.软件包的安装 1.rpm安装,rpm安装分为俩种,一种是直接安装xxx.rpm包,另一种是通过yum安装一系列的rpm包. #推荐使用yum安装,y ...

  5. C#操作excel(多种方法比较)

    1.用查询表的方式查询并show在数据集控件上. public static string strCon = " Provider = Microsoft.Jet.OLEDB.4.0 ; D ...

  6. 快速开发android,离不开这10个优秀的开源项目

    作为一名菜鸡Android,时常瞻仰大佬们的开源项目是非常必要的.这里我为大家收集整理了10个优秀的开源项目,方便我们日常开发中学习! 作者:ListenToCode博客:https://www.ji ...

  7. 年底Android面试整理(附答案)

    面试,无非都是问上面这些问题(挺多的 - -!),聘请中高级的安卓开发会往深的去问,并且会问一延伸二.以下我先提出几点重点,是面试官基本必问的问题,请一定要去了解! 基础知识 – 四大组件(生命周期, ...

  8. 来,了解一下Java内存模型(JMM)

    网上有很多关于Java内存模型的文章,在<深入理解Java虚拟机>和<Java并发编程的艺术>等书中也都有关于这个知识点的介绍.但是,很多人读完之后还是搞不清楚,甚至有的人说自 ...

  9. Confluence 6 恢复一个站点有关使用站点导出为备份的说明

    推荐使用生产备份策略.我们推荐你针对你的生产环境中使用的 Confluence 参考 Production Backup Strategy 页面中的内容进行备份和恢复(这个需要你备份你的数据库和 ho ...

  10. ActiveMQ消息的发送原理

    持久化消息和非持久化消息的发送策略:消息同步发送和异步发送 ActiveMQ支持同步.异步两种发送模式将消息发送到broker上.同步发送过程中,发送者发送一条消息会阻塞直到broker反馈一个确认消 ...