CF1208H Red Blue Tree

原本应该放在这里但是这题过于毒瘤。。单独开了篇blog

首先考虑如果 $ k $ 无限小,那么显然整个树都是蓝色的。随着 $ k $ 逐渐增大,每个点都会有且仅有一次变色,我们考虑维护这个变色的时间 $ t $ 。如果每个点的变色时间都已经被算出来,那么我们可以轻易解决题目的查询操作和修改 $ k $ , 也就是说修改 $ k $ 本身就是个假操作。。只需要考虑的是修改单点颜色。

修改单点颜色,看起来就很 $ ddp $ 。树链剖分后,用$ f(x) = {a,b} $ 表示点 $ x $ 重儿子是 R 时的临界值是 $ a $ ,重儿子是 B 时临界值是 $ b $ 。

发现 $ f $ 这个东西是可以合并的!于是可以愉快地用线段树维护了呢~

但是除开重儿子怎么做呢,考虑每个点再开一个 BST 维护轻儿子当前的边界值。这个可以预处理的时候实现。同时我们意识到 $ \sum x $ ( $ x $ 是边界值 ) 是 $ n $ 级别的,所以我们可以对于每个点暴力出最开始的边界。具体的暴力方法是在build链剖后的线段树时先处理右子树,这样总可以保证处理到一个点时它的轻儿子都已经被插入到了它自己的平衡树,然后直接枚举边界值在平衡树判断就好了。

由于每次修改一个叶子,它的祖先的边界变化量是 $ O(1) $ 的,所以修改的复杂度是 $ O(log^2n) $

只是很难写

Orz LJZ_C 吊踩标算

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. #define MAXN 200006
  7. int n , k;
  8. #define Update( cur ) if( cur -> left -> size ) cur -> size = cur -> left -> size + cur -> right -> size , cur -> value = cur -> right -> value
  9. #define new_Node( s , v , a , b ) ( & ( * st[ cnt++ ] = Node( s , v , a , b ) ) )
  10. #define Merge( a , b ) new_Node( a -> size + b -> size , b -> value , a , b )
  11. #define ratio 4
  12. namespace BST {
  13. int cnt , s , a;
  14. struct Node {
  15. int size , value;
  16. Node * left , * right;
  17. Node( int s , int v , Node * a , Node * b ) : size( s ) , value( v ) , left( a ) , right( b ) {}
  18. Node() {}
  19. } * root[1000000] , * father , * st[1000000] , t[1000000] , * null;
  20. inline void maintain( register Node * cur ) {
  21. if( cur -> left -> size > cur -> right -> size * ratio ) cur -> right = Merge( cur -> left -> right , cur -> right ) , st[ --cnt ] = cur -> left , cur -> left = cur -> left -> left;
  22. if( cur -> right -> size > cur -> left -> size * ratio ) cur -> left = Merge( cur -> left , cur -> right -> left ) , st[ --cnt ] = cur -> right , cur -> right = cur -> right -> right;
  23. }
  24. int find( int x , Node * cur ) {
  25. if( cur -> size == 1 ) return cur -> value;
  26. return x > cur -> left -> size ? find( x - cur -> left -> size , cur -> right ) : find( x , cur -> left );
  27. }
  28. int Rank( int x , Node * cur ) {
  29. if( cur -> size == 1 ) return 1;
  30. return x > cur -> left -> value ? Rank( x , cur -> right ) + cur -> left -> size : Rank( x , cur -> left );
  31. }
  32. void insert( int x , Node * cur ) {
  33. if( cur -> size == 1 ) cur -> left = new_Node( 1 , min( cur -> value , x ) , null , null ) , cur -> right = new_Node( 1 , max( cur -> value , x ) , null , null );
  34. else insert( x , x > cur -> left -> value ? cur -> right : cur -> left );
  35. Update( cur );
  36. maintain( cur );
  37. }
  38. void erase( int x , Node * cur ) {
  39. if( cur -> size == 1 ) * father = cur == father -> left ? * father -> right : * father -> left;
  40. else father = cur , erase( x , x > cur -> left -> value ? cur -> right : cur -> left );
  41. Update( cur );
  42. maintain( cur );
  43. }
  44. void init( ) {
  45. null = new Node( 0 , 0 , 0 , 0 );
  46. for( int i = 0 ; i < 1000000 ; ++ i ) st[i] = & t[i] , root[i] = new Node( 1 , 0x7f7f7f7f , null , null );
  47. }
  48. }
  49. int head[MAXN] , nex[MAXN << 1] , to[MAXN << 1] , ecn = 0;
  50. void ade( int u , int v ) {
  51. nex[++ecn] = head[u] , to[ecn] = v , head[u] = ecn;
  52. }
  53. int fa[MAXN] , siz[MAXN] , hea[MAXN] , dep[MAXN] , top[MAXN] , tig[MAXN] , bac[MAXN] , en[MAXN] , clo;
  54. void dfs( int u , int faa ) {
  55. siz[u] = 1 , dep[u] = dep[faa] + 1;
  56. for( int i = head[u] ; i ; i = nex[i] ) {
  57. int v = to[i];
  58. if( v == faa ) continue;
  59. fa[v] = u;
  60. dfs( v , u );
  61. siz[u] += siz[v];
  62. if( !hea[u] || siz[v] > siz[hea[u]] ) hea[u] = v;
  63. }
  64. }
  65. void dfss( int u , int too ) {
  66. tig[u] = ++ clo , bac[clo] = u , en[too] = u , top[u] = too;
  67. if( !hea[u] ) return;
  68. dfss( hea[u] , too );
  69. for( int i = head[u] ; i ; i = nex[i] ) {
  70. int v = to[i];
  71. if( v == fa[u] || v == hea[u] ) continue;
  72. dfss( v , v );
  73. }
  74. }
  75. int col[MAXN];
  76. struct node{
  77. int l , r;
  78. node( int L = 0 , int R = 0 ) : l(L) , r(R) { }
  79. } T[MAXN << 2] , red( 0x3f3f3f3f , 0x3f3f3f3f ) , blu( -0x3f3f3f3f , -0x3f3f3f3f ) ;
  80. int rec[MAXN];
  81. // T[rt].l : if rt's heavy son is red , the value k to satisfy that this node is red
  82. // T[rt].r : if rt's heavy son is blu , the value k to satisfy that this node is red
  83. // b : 0 , r : 1
  84. bool judge( int u , int k , int d ) {
  85. // return we add d red nodes to its son if the node is red.
  86. int B = BST :: Rank( k + 1 , BST :: root[u] ) - 1;
  87. int R = BST :: Rank( 0x7f7f7f7f , BST :: root[u] ) - 1 - B;
  88. return k >= R - B - d;
  89. }
  90. void update( int u , int& k , int d ) {
  91. while( !judge( u , k , d ) ) ++ k;
  92. while( judge( u , k - 1 , d ) ) -- k;
  93. }
  94. void work( int rt , int u ) {
  95. if( col[u] == 0 ) {
  96. T[rt] = red;
  97. } else if( col[u] == 1 ) {
  98. T[rt] = blu;
  99. } else {
  100. update( u , T[rt].l , 1 );
  101. update( u , T[rt].r , -1 );
  102. }
  103. }
  104. node merge( node a , node b ) {
  105. node ret;
  106. ret.l = min( max( b.l , a.l ) , a.r );
  107. ret.r = min( max( b.r , a.l ) , a.r );
  108. return ret;
  109. }
  110. void pushup( int rt ) {
  111. T[rt] = merge( T[rt << 1] , T[rt << 1 | 1] );
  112. }
  113. node query( int rt , int l , int r , int L , int R ) {
  114. if( l == L && r == R ) return T[rt];
  115. int m = l + r >> 1;
  116. if( R <= m ) return query( rt << 1 , l , m , L , R );
  117. if( L > m ) return query( rt << 1 | 1 , m + 1 , r , L , R );
  118. return merge( query( rt << 1 , l , m , L , m ) , query( rt << 1 | 1 , m + 1 , r , m + 1 , R ) );
  119. }
  120. void build( int rt , int l , int r ) {
  121. if( l == r ) {
  122. int u = bac[l];
  123. work( rt , u );
  124. if( u == top[u] && fa[u] )
  125. BST :: insert( ( rec[u] = ( query( 1 , 1 , n , l , tig[en[u]] ) ).l ) , BST :: root[fa[u]] );
  126. return;
  127. }
  128. int mid = l + r >> 1;
  129. build( rt << 1 | 1 , mid + 1 , r ) , build( rt << 1 , l , mid );
  130. pushup( rt );
  131. }
  132. void mdfy( int rt , int l , int r , int p ) {
  133. if( l == r ) { work( rt , bac[l] ); return; }
  134. int m = l + r >> 1;
  135. if( p <= m ) mdfy( rt << 1 , l , m , p );
  136. else mdfy( rt << 1 | 1 , m + 1 , r , p );
  137. pushup( rt );
  138. }
  139. void modify( int x , int c ) {
  140. col[x] = c;
  141. while( x ) {
  142. mdfy( 1 , 1 , n , tig[x] );
  143. x = top[x];
  144. if( fa[x] != 0 ) {
  145. BST :: erase( rec[x] , BST :: root[fa[x]] );
  146. BST :: insert( rec[x] = (query( 1 , 1 , n , tig[x] , tig[en[x]] ).l ) , BST :: root[fa[x]] );
  147. }
  148. x = fa[x];
  149. }
  150. }
  151. int main() {
  152. BST :: init( );
  153. cin >> n >> k;
  154. for( int i = 1 , u , v ; i < n ; ++ i ) {
  155. scanf("%d%d",&u,&v);
  156. ade( u , v ) , ade( v , u );
  157. }
  158. for( int i = 1 ; i <= n ; ++ i ) scanf("%d",&col[i]);
  159. dfs( 1 , 1 );
  160. dfss( 1 , 1 );
  161. build( 1 , 1 , n );
  162. int q , opt , v , c; cin >> q;
  163. while( q-- ) {
  164. scanf("%d",&opt);
  165. if( opt == 1 ) {
  166. scanf("%d",&v);
  167. printf("%d\n",( query( 1 , 1 , n , tig[v] , tig[en[top[v]]] ).l ) <= -k);
  168. } else if( opt == 2 ) {
  169. scanf("%d%d",&v,&c);
  170. modify( v , c );
  171. } else {
  172. scanf("%d",&c);
  173. k = c;
  174. }
  175. }
  176. }

CF1208H Red Blue Tree的更多相关文章

  1. CF1208 Red Blue Tree

    题目链接 问题分析 这是蒟蒻第一道3500!不过话说luogu上两个题解的程序都是假的可还行(2019.11.1)-- 为了方便叙述,下面我们约定 : \([c]\) 的值为 \(1\) 当且仅当 \ ...

  2. BNUOJ 26229 Red/Blue Spanning Tree

    Red/Blue Spanning Tree Time Limit: 2000ms Memory Limit: 131072KB This problem will be judged on HDU. ...

  3. Red–black tree ---reference wiki

    source address:http://en.wikipedia.org/wiki/Red%E2%80%93black_tree A red–black tree is a type of sel ...

  4. [转载] 红黑树(Red Black Tree)- 对于 JDK TreeMap的实现

    转载自http://blog.csdn.net/yangjun2/article/details/6542321 介绍另一种平衡二叉树:红黑树(Red Black Tree),红黑树由Rudolf B ...

  5. Red Black Tree 红黑树 AVL trees 2-3 trees 2-3-4 trees B-trees Red-black trees Balanced search tree 平衡搜索树

    小结: 1.红黑树:典型的用途是实现关联数组 2.旋转 当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质.为了保持红黑树的性质,我们可以通过对树进行旋转,即修改树中某些 ...

  6. 2018 ICPC青岛网络赛 B. Red Black Tree(倍增lca好题)

    BaoBao has just found a rooted tree with n vertices and (n-1) weighted edges in his backyard. Among ...

  7. 计蒜客 Red Black Tree(树形DP)

    You are given a rooted tree with n nodes. The nodes are numbered 1..n. The root is node 1, and m of ...

  8. Red Black Tree(红黑树)

    (修改于 2018-05-06 15:53:22 还差删除维护操作.层序遍历没完成.维护操作没完成不想写层序遍历怎么办...) 今天下午完成了红黑树的插入的维护操作,但删除的维护操作还没有解决,删除的 ...

  9. ZOJ - 4048 Red Black Tree (LCA+贪心) The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online

    题意:一棵树上有m个红色结点,树的边有权值.q次查询,每次给出k个点,每次查询有且只有一次机会将n个点中任意一个点染红,令k个点中距离红色祖先距离最大的那个点的距离最小化.q次查询相互独立. 分析:数 ...

随机推荐

  1. Beta阶段第十次会议

    Beta阶段第十次会议 时间:2020.5.26 完成工作 姓名 完成工作 难度 完成度 ltx 1.修正小程序新闻bug2.修正小程序认证bug 中 80% xyq 1.上传信息编辑部分代码到服务器 ...

  2. flutter页面间跳转和传参-Navigator的使用

    flutter页面间跳转和传参-Navigator的使用 概述 flutter中的默认导航分成两种,一种是命名的路由,一种是构建路由. 命名路由 这种路由需要一开始现在创建App的时候定义 new M ...

  3. 零基础玩转C语言单链表

    下图为最一简单链表的示意图: 第 0 个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量.以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学号 num,姓名 n ...

  4. 【做题记录】CF1444A Division

    CF1444A Division 题意: 给定 \(t\) 组询问,每组给两个数 \(p_i\) 和 \(q_i\) ,找出最大的整数 \(x_i\) ,要求 \(p_i\) 可被 \(x_i\) 整 ...

  5. 恶意代码分析实战四:IDA Pro神器的使用

    目录 恶意代码分析实战四:IDA Pro神器的使用 实验: 题目1:利用IDA Pro分析dll的入口点并显示地址 空格切换文本视图: 带地址显示图形界面 题目2:IDA Pro导入表窗口 题目3:交 ...

  6. 非对称加密和linux上的 ssh-keygen 工具使用

    rsa :创造非对称加密的三个人名.原理是两个1024到2048之间的素数,以此为乘积.等... a*b=c  一般a*b为私钥端,c为公钥端.因为 c非常难算出a和b. ssh-keygen -t ...

  7. Oracle SQL注入 总结

    0x00 Oracle基础 Oracle 基本使用 什么是Oracle数据库? Oracle公司目前是世界上最大的软件提供商之一,与它并列的还有 Microsoft与 Adode.并且随着 Oracl ...

  8. springboot单元测试 JUnit5

    JUnit5简介 Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库 JUnit 5官方文档 作为最新版本的JUnit框架,JUnit5与之前版本的JUnit框架有很 ...

  9. 数组 & 对象 & 函数

    数组 数组也是一个对象,不同的是对象用字符串作为属性名,而数组用数字作为索引,数组的索引从0开始 创建数组: //方式一:构造器,可以在创建数组时指定 Var arr = new Array(1,2, ...

  10. yaml基本用法

    简介 YAML 是 "YAML Ain't Markup Language"(YAML 不是一种标记语言)的递归缩写.在开发的这种语言时,YAML 的意思其实是:"Yet ...