考虑如下构造:

新建一条边$(0,1)$,并将原树以0为根建树,记$fa_{x}$为$x$的父亲(其中$1\le x\le n$)

维护两棵森林,分别记作$T_{0/1}$,每一条边恰属于一棵,其中$(x,fa_{x})\in T_{0}$当且仅当$x$为白色点

此时,考虑节点$x$的答案(不妨假设$x$为白色点),即是$T_{0}$去掉$x$所在连通块根节点(深度最小的节点)后所在连通块子树大小,正确性显然

对这两棵森林使用LCT维护,考虑修改和查询:

1.修改时,即增加并删除一条边

2.查询时,不妨假设$x$为白色,将$T_{0}$中$x$所在连通块内深度最小的点make_root后,不难发现即求该点右儿子子树范围内的点数,显然容易维护("子树范围"定义以及如何维护见QTREE5

考虑如何快速找到该点,考虑保持树的形态(注意初始状态),即在make_root时不rev,那么find_root的结果即为该最浅的点

这样在加边和删边时并不会产生影响(其实通常的LCT在加边和删边时也并不需要rev),查询时的做法上面已经给出,即find_root一下即可

时间复杂度为$o(n\log n)$,可以通过

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N 100005
  4. 4 vector<int>v[N];
  5. 5 int n,m,x,y,f[N],col[N];
  6. 6 struct LCT{
  7. 7 int fa[N],vir[N],sz[N],ch[N][2];
  8. 8 LCT(){
  9. 9 for(int i=1;i<N;i++)sz[i]=1;
  10. 10 }
  11. 11 bool check(int k){
  12. 12 return ((ch[fa[k]][0]!=k)&&(ch[fa[k]][1]!=k));
  13. 13 }
  14. 14 int which(int k){
  15. 15 return ch[fa[k]][1]==k;
  16. 16 }
  17. 17 void up(int k){
  18. 18 sz[k]=sz[ch[k][0]]+sz[ch[k][1]]+vir[k]+1;
  19. 19 }
  20. 20 void add_vir(int k){
  21. 21 vir[fa[k]]+=sz[k];
  22. 22 }
  23. 23 void del_vir(int k){
  24. 24 vir[fa[k]]-=sz[k];
  25. 25 }
  26. 26 void rotate(int k){
  27. 27 int f=fa[k],g=fa[f],p=which(k);
  28. 28 fa[k]=g;
  29. 29 if (!check(f))ch[g][which(f)]=k;
  30. 30 fa[ch[k][p^1]]=f,ch[f][p]=ch[k][p^1];
  31. 31 fa[f]=k,ch[k][p^1]=f;
  32. 32 up(f),up(k);
  33. 33 }
  34. 34 void splay(int k){
  35. 35 for(int i=fa[k];!check(k);i=fa[k]){
  36. 36 if (!check(i)){
  37. 37 if (which(i)==which(k))rotate(i);
  38. 38 else rotate(k);
  39. 39 }
  40. 40 rotate(k);
  41. 41 }
  42. 42 }
  43. 43 void access(int k){
  44. 44 int lst=0;
  45. 45 while (k){
  46. 46 splay(k);
  47. 47 if (ch[k][1])add_vir(ch[k][1]);
  48. 48 if (lst)del_vir(lst);
  49. 49 ch[k][1]=lst,up(k);
  50. 50 lst=k,k=fa[k];
  51. 51 }
  52. 52 }
  53. 53 void make_root(int k){
  54. 54 access(k);
  55. 55 splay(k);
  56. 56 }
  57. 57 int find_root(int k){
  58. 58 access(k);
  59. 59 splay(k);
  60. 60 while (ch[k][0])k=ch[k][0];
  61. 61 splay(k);
  62. 62 return k;
  63. 63 }
  64. 64 void add(int x,int y){
  65. 65 make_root(x);
  66. 66 make_root(y);
  67. 67 fa[y]=x,add_vir(y),up(x);
  68. 68 }
  69. 69 void del(int x,int y){
  70. 70 make_root(x);
  71. 71 access(y);
  72. 72 fa[y]=ch[x][1]=0,up(x);
  73. 73 }
  74. 74 int query(int k){
  75. 75 k=find_root(k);
  76. 76 return sz[ch[k][1]];
  77. 77 }
  78. 78 }T[2];
  79. 79 void dfs(int k,int fa){
  80. 80 f[k]=fa;
  81. 81 for(int i=0;i<v[k].size();i++)
  82. 82 if (v[k][i]!=fa)dfs(v[k][i],k);
  83. 83 }
  84. 84 int main(){
  85. 85 scanf("%d",&n);
  86. 86 for(int i=1;i<n;i++){
  87. 87 scanf("%d%d",&x,&y);
  88. 88 v[x].push_back(y);
  89. 89 v[y].push_back(x);
  90. 90 }
  91. 91 dfs(1,n+1);
  92. 92 for(int i=1;i<=n;i++){
  93. 93 col[i]=1;
  94. 94 T[1].add(f[i],i);
  95. 95 }
  96. 96 scanf("%d",&m);
  97. 97 for(int i=1;i<=m;i++){
  98. 98 scanf("%d%d",&x,&y);
  99. 99 if (!x)printf("%d\n",T[col[y]].query(y));
  100. 100 else{
  101. 101 T[col[y]].del(f[y],y);
  102. 102 col[y]^=1;
  103. 103 T[col[y]].add(f[y],y);
  104. 104 }
  105. 105 }
  106. 106 return 0;
  107. 107 }

[spojQTREE6]Query on a tree VI的更多相关文章

  1. bzoj 3637: Query on a tree VI 树链剖分 && AC600

    3637: Query on a tree VI Time Limit: 8 Sec  Memory Limit: 1024 MBSubmit: 206  Solved: 38[Submit][Sta ...

  2. QTREE6 - Query on a tree VI 解题报告

    QTREE6 - Query on a tree VI 题目描述 给你一棵\(n\)个点的树,编号\(1\)~\(n\).每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我 ...

  3. bzoj3637: Query on a tree VI

    Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree node ...

  4. BZOJ3637 Query on a tree VI(树链剖分+线段树)

    考虑对于每一个点维护子树内与其连通的点的信息.为了换色需要,记录每个点黑白两种情况下子树内连通块的大小. 查询时,找到深度最浅的同色祖先即可,这可以比较简单的树剖+线段树乱搞一下(似乎就是qtree3 ...

  5. SPOJ QTREE Query on a tree VI

    You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are number ...

  6. [BZOJ 3637]Query on a tree VI

    偶然看见了这题,觉得自己 QTREE.COT 什么的都没有刷过的真是弱爆了…… 一道思路很巧妙的题,终于是在约大爷的耐心教导下会了,真是太感谢约大爷了. 这题显然是树链剖分,但是链上维护的东西很恶心. ...

  7. QTREE6&&7 - Query on a tree VI &&VII

    树上连通块 不用具体距离,只询问连通块大小或者最大权值 可以类比Qtree5的方法,但是记录东西很多,例如子树有无0/1颜色等 一个trick,两个LCT分离颜色 每个颜色在边上. 仅保留连通块顶部不 ...

  8. 2019.02.17 spoj Query on a tree VI(链分治)

    传送门 题意简述:给你一棵nnn个黑白点的树,支持改一个点的颜色,询问跟某个点颜色相同的连通块大小. 思路: 还是链分治 233 记fi,0/1f_{i,0/1}fi,0/1​表示iii的所有颜色为0 ...

  9. [CodeChef-QTREE6]Query on a tree VI

    题目大意: 给你一棵黑白树,每个点默认是白色,要求支持以下两种操作: 1.改变一个点的颜色: 2.除去连接不同颜色的点的边,求某个点连通块的大小. 思路: 对原树维护两个树链剖分, 一棵维护当点x为白 ...

随机推荐

  1. Java JDK的下载与安装!Java基础

    在了解什么是Java.Java 语言的特点以及学习方法之后,本节将介绍如何搭建编写 Java 程序所需要的开发环境--JDK,只有搭建了环境才能敲代码! 学Java的都知道,JDK 是一种用于构建在 ...

  2. UDP接收端和发送端_Socket编程

    UDP接收端 接收端启动文件 1 import java.net.DatagramSocket; 2 import java.net.SocketException; 3 4 public class ...

  3. SudokuSolver 2.0:用C++实现的数独解题程序 【一】

    SudokuSolver 2.0 实现效果 H:\Read\num\Release>sudoku.exe Order please: Sudoku Solver 2.0 2021/10/2 by ...

  4. 3.4 Common Principles 通用原则

    3.4 Common Principles 通用原则 Before going into details, let's see some overall DDD principles; 在讨论细节之前 ...

  5. nsq - 一条消息的生命周期(一)

    经过前面几篇的学习,相信大家对nsq已经有了一个大概的了解,我在写这篇文章的时候也看了很多其他人写的教程,发现大家对于分析系统每个点写的很不错,但是都很少有整体串起来一起走一遍,所以,我打算分成2-3 ...

  6. [对对子队]会议记录4.14(Scrum Meeting 5)

    今天已完成的工作 刘子航 ​ 工作内容:设计第2,3关 ​ 相关issue:设计关卡2,3 吴昭邦 ​ 工作内容:制作场景,暂时解决了坐标错位问题 ​ 相关issue:实现游戏场景中的必要模型 何瑞 ...

  7. Spring Cloud Alibaba 使用Nacos作为服务注册中心

    为什么需要注册中心? 在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就到这里找到服务的地址,进行调用:服务管理,核心是有个服务注册表,心跳机制动态维护 : 服务注册 创建普通Spring ...

  8. python +spatialite + window 解决方案(https://www.jianshu.com/p/5bc7d8b7b429)

    运行环境在windows 10 64bit.先将python安装完成.然后,到 spatilite官网 找到MS(即Microsoft)版本,下载64位的mod_spatialite,将其先解压到目标 ...

  9. SpringCloud 2020.0.4 系列之Hystrix看板

    1. 概述 老话说的好:沉默是金,有时适当的沉默,比滔滔不绝更加有效. 言归正传,前面我们聊了有关 Hystrix 降级熔断的话题,今天我们来聊聊如何使用 turbine 和 hystrix dash ...

  10. Myod 选做

    一.题目要求 1.复习c文件处理内容 2.编写myod.c 用myod XXX实现Linux下od -tc -tx XXX的功能 3.main与其他分开,制作静态库和动态库 4.编写Makefile ...