题意:给定一棵树,每个节点可以变成黑白两色。一开始所有节点都是黑色,操作可将点颜色改变,询问当前情况下距离最远的两个黑点的距离。

动态树分治。一开始想的是对于每个节点维护主大和次大,后来发现这实在是太NAIVE了。实际上,正解是这样的:

对于每个点,维护两个堆(接下来说的都是点分树上的节点):第一个堆,该点子树到该点父亲的距离,第二个堆,该点直接儿子的第一个堆的堆顶元素。

然后我们再开一个全局堆,即答案堆,维护所有第二个堆最大和次大之和。每次询问只要把堆顶元素拿出来就可以了。

为什么空间开的下呢?这个道理和震波那道题是一样的,考虑点分治的时间复杂度,每个点最大堆空间开到的就是该点子树大小,总和是nlogn的,完全开的下。

怎么修改呢,暴力爬树高啊,点分树不就是这一点树高稳定log最好吗!

维护3个堆的过程特别繁琐,写的时候写了一个上午。。。就为了那几个if。。

最后被自己模拟的堆坑了一发。。改到现在才过

上代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define N 100005
  4. #define INF 1e9
  5. inline int read(){
  6. int x=,f=; char a=getchar();
  7. while(a<'' || a>'') {if(a=='') f=-; a=getchar();}
  8. while(a>='' && a<='') x=x*+a-'',a=getchar();
  9. return x*f;
  10. }
  11. int n,q,head[N],s[N],cnt,f[N],rt,sz,dep[N],fa[N][],dis[N][],now;
  12. char ch[]; bool vis[N],on[N];
  13. struct heap{
  14. priority_queue<int>A,B;
  15. void push(int x) {A.push(x);}
  16. void erase(int x) {B.push(x);}
  17. void pop() {while(B.size()&&A.top()==B.top()) A.pop(),B.pop(); A.pop();}
  18. int top() {while(B.size()&&A.top()==B.top()) A.pop(),B.pop(); if(A.size()) return A.top(); else return -INF;}
  19. int size() {return A.size()-B.size();}
  20. int s_top(){ if(size()<) return -INF;
  21. while(B.size()&&A.top()==B.top()) A.pop(),B.pop();
  22. int t=A.top(),ret; A.pop();
  23. while(B.size()&&A.top()==B.top()) A.pop(),B.pop();
  24. ret=A.top(); A.push(t);
  25. return ret;
  26. }
  27. }C,A[N],B[N];
  28. struct edges{
  29. int to,next;
  30. }e[*N];
  31. void insert(){
  32. int u=read(),v=read();
  33. e[cnt]=(edges){v,head[u]};head[u]=cnt++;
  34. e[cnt]=(edges){u,head[v]};head[v]=cnt++;
  35. }
  36. void getroot(int x,int p){
  37. s[x]=; f[x]=;
  38. for(int i=head[x];i>=;i=e[i].next){
  39. if(vis[e[i].to] || p==e[i].to) continue;
  40. getroot(e[i].to,x); s[x]+=s[e[i].to];
  41. f[x]=max(f[x],s[e[i].to]);
  42. }
  43. f[x]=max(f[x],sz-s[x]);
  44. if(f[rt]>f[x]) rt=x;
  45. }
  46. void getship(int x,int anc,int p,int d){
  47. for(int v,i=head[x];i>=;i=e[i].next){
  48. v=e[i].to;
  49. if(vis[v] || p==v) continue;
  50. fa[v][++dep[v]]=anc; dis[v][dep[v]]=d; getship(v,anc,x,d+);
  51. }
  52. }
  53. void buildtree(int x){
  54. vis[x]=; getship(x,x,,); int all=sz;
  55. for(int i=head[x];i>=;i=e[i].next){
  56. if(vis[e[i].to]) continue;
  57. if(s[e[i].to]>s[x]) s[e[i].to]=all-s[x]; sz=s[e[i].to];
  58. rt=; getroot(e[i].to,x); buildtree(rt);
  59. }
  60. }
  61. void turn_off(int x){
  62. B[x].push();
  63. if(B[x].size()==) C.push(B[x].top());
  64. for(int t,pre,i=dep[x];i>;i--){
  65. if(!A[fa[x][i]].size()){
  66. A[fa[x][i]].push(dis[x][i-]);
  67. pre=B[fa[x][i-]].top()+B[fa[x][i-]].s_top();
  68. B[fa[x][i-]].push(dis[x][i-]);
  69. if(pre> && pre==B[fa[x][i-]].top()+B[fa[x][i-]].s_top()) continue;
  70. if(pre> && pre!=B[fa[x][i-]].top()+B[fa[x][i-]].s_top())
  71. C.erase(pre),C.push(B[fa[x][i-]].top()+B[fa[x][i-]].s_top());
  72. else if(B[fa[x][i-]].top()+B[fa[x][i-]].s_top()>) C.push(B[fa[x][i-]].top()+B[fa[x][i-]].s_top());
  73. }else{
  74. t=A[fa[x][i]].top(); A[fa[x][i]].push(dis[x][i-]);
  75. if(t<dis[x][i-]){
  76. pre=B[fa[x][i-]].top()+B[fa[x][i-]].s_top();
  77. B[fa[x][i-]].erase(t); B[fa[x][i-]].push(dis[x][i-]);
  78. if(pre> && pre!=B[fa[x][i-]].top()+B[fa[x][i-]].s_top())
  79. C.erase(pre),C.push(B[fa[x][i-]].top()+B[fa[x][i-]].s_top());
  80. }
  81. }
  82. }
  83. }
  84. void turn_on(int x){
  85. B[x].erase();
  86. if(B[x].size()==) C.erase(B[x].top());
  87. for(int t,pre,i=dep[x];i>;i--){
  88. A[fa[x][i]].erase(dis[x][i-]);
  89. if(A[fa[x][i]].top()<dis[x][i-]) {
  90. pre=B[fa[x][i-]].top()+B[fa[x][i-]].s_top();
  91. B[fa[x][i-]].erase(dis[x][i-]);
  92. if(A[fa[x][i]].size()) B[fa[x][i-]].push(A[fa[x][i]].top());
  93. if(pre>) {
  94. if(pre==B[fa[x][i-]].top()+B[fa[x][i-]].s_top()) continue;
  95. C.erase(pre);
  96. if(B[fa[x][i-]].size()>)
  97. C.push(B[fa[x][i-]].top()+B[fa[x][i-]].s_top());
  98. }
  99. }
  100. }
  101. }
  102. inline void change(int x){
  103. if(!on[x]) turn_on(x);
  104. else turn_off(x);
  105. on[x]^=;
  106. if(on[x]) now++;
  107. else now--;
  108. }
  109. int main(){
  110. n=read(); memset(head,-,sizeof(head));
  111. for(int i=;i<n;i++) insert();
  112. f[]=INF; sz=n; getroot(,); buildtree(rt);
  113. for(int i=;i<=n;i++) fa[i][++dep[i]]=i,turn_off(i);
  114. q=read();
  115. while(q--){
  116. scanf("%s",ch);
  117. if(ch[]=='G') {
  118. if(now==n) puts("-1");
  119. else printf("%d\n",max(C.top(),));
  120. }
  121. else change(read());
  122. }
  123. return ;
  124. }

1095: [ZJOI2007]Hide 捉迷藏的更多相关文章

  1. 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)

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

  2. 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏

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

  3. BZOJ 1095: [ZJOI2007]Hide 捉迷藏

    Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...

  4. bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...

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

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

  6. 【BZOJ】1095: [ZJOI2007]Hide 捉迷藏 括号序列+线段树

    [题目]BZOJ 1095 [题意]给定n个黑白点的树,初始全为黑点,Q次操作翻转一个点的颜色,或询问最远的两个黑点的距离,\(n \leq 10^5,Q \leq 5*10^5\). [算法]括号序 ...

  7. 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV

    意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...

  8. BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)

    这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...

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

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

随机推荐

  1. Android APK反编译详解(附图)

    转载自http://blog.csdn.net/sunboy_2050/article/details/6727581 这段时间在学Android应用开发,在想既然是用Java开发的应该很好反编译从而 ...

  2. C语言 在VS环境下一个很有意思的报错:stack around the variable was corrupted

    今天做一个很简单的oj来温习下c 语言 题目如下 输入 3位正整数 输出 逆置后的正整数 代码如下: #include"stdio.h"int main(){ float h,su ...

  3. MySQL functions, IF, CASE

    MySQLTutorial官网 IF function syntax: IF(expr,if_true_expr,if_false_expr) CASE expression syntax: CASE ...

  4. ReactiveCocoa常见操作方法介绍/MVVM架构思想

      1.ReactiveCocoa常见操作方法介绍. 1.1 ReactiveCocoa操作须知 所有的信号(RACSignal)都可以进行操作处理,因为所有操作方法都定义在RACStream.h中, ...

  5. [转]SOCKET通信中TCP、UDP数据包大小的确定

    TCP.UDP数据包大小的确定 UDP和TCP协议利用端口号实现多项应用同时发送和接收数据.数据通过源端口发送出去,通过目标端口接收.有的网络应用只能使用预留或注册的静态端口:而另外一些网络应用则可以 ...

  6. eclipse 设置jsp页面为HTML5

    window-preferences-web-jspFiles-Editor-Templates-jsp with html... 然后修改为<!DOCTYPE html>就行了

  7. solr初学

    1.我按照网上说的,先去下载了一个版本的额solr.solr-5.4.1 首先有些让我先配饰tomcat,我之前没有接触过solr所以先没去看如何配置,估计也和jdk的配置差不多. 2.下载好后我也想 ...

  8. python字符串加颜色区别

    1.有时需要显目的区别不同内容,可以改变显目的内容颜色 print("\033[31;1m你好麽,\033[0m我很好..")print("\033[32;1m你好麽,\ ...

  9. JavaScript中的prototype使用说明

    参考 http://abruzzi.iteye.com/blog/1026125 http://www.jb51.net/article/23052.htm

  10. mac 终端 svn 命令(转)

    mac 终端 svn 命令 1.将文件checkout到本地目录 svn checkout path(path是服务器上的目录)   例如:svn checkout svn://192.168.1.1 ...