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 吊踩标算

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200006
int n , k; #define Update( cur ) if( cur -> left -> size ) cur -> size = cur -> left -> size + cur -> right -> size , cur -> value = cur -> right -> value
#define new_Node( s , v , a , b ) ( & ( * st[ cnt++ ] = Node( s , v , a , b ) ) )
#define Merge( a , b ) new_Node( a -> size + b -> size , b -> value , a , b )
#define ratio 4
namespace BST {
int cnt , s , a;
struct Node {
int size , value;
Node * left , * right;
Node( int s , int v , Node * a , Node * b ) : size( s ) , value( v ) , left( a ) , right( b ) {}
Node() {}
} * root[1000000] , * father , * st[1000000] , t[1000000] , * null; inline void maintain( register Node * cur ) {
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;
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;
} int find( int x , Node * cur ) {
if( cur -> size == 1 ) return cur -> value;
return x > cur -> left -> size ? find( x - cur -> left -> size , cur -> right ) : find( x , cur -> left );
} int Rank( int x , Node * cur ) {
if( cur -> size == 1 ) return 1;
return x > cur -> left -> value ? Rank( x , cur -> right ) + cur -> left -> size : Rank( x , cur -> left );
} void insert( int x , Node * cur ) {
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 );
else insert( x , x > cur -> left -> value ? cur -> right : cur -> left );
Update( cur );
maintain( cur );
} void erase( int x , Node * cur ) {
if( cur -> size == 1 ) * father = cur == father -> left ? * father -> right : * father -> left;
else father = cur , erase( x , x > cur -> left -> value ? cur -> right : cur -> left );
Update( cur );
maintain( cur );
} void init( ) {
null = new Node( 0 , 0 , 0 , 0 );
for( int i = 0 ; i < 1000000 ; ++ i ) st[i] = & t[i] , root[i] = new Node( 1 , 0x7f7f7f7f , null , null );
} } int head[MAXN] , nex[MAXN << 1] , to[MAXN << 1] , ecn = 0;
void ade( int u , int v ) {
nex[++ecn] = head[u] , to[ecn] = v , head[u] = ecn;
}
int fa[MAXN] , siz[MAXN] , hea[MAXN] , dep[MAXN] , top[MAXN] , tig[MAXN] , bac[MAXN] , en[MAXN] , clo;
void dfs( int u , int faa ) {
siz[u] = 1 , dep[u] = dep[faa] + 1;
for( int i = head[u] ; i ; i = nex[i] ) {
int v = to[i];
if( v == faa ) continue;
fa[v] = u;
dfs( v , u );
siz[u] += siz[v];
if( !hea[u] || siz[v] > siz[hea[u]] ) hea[u] = v;
}
}
void dfss( int u , int too ) {
tig[u] = ++ clo , bac[clo] = u , en[too] = u , top[u] = too;
if( !hea[u] ) return;
dfss( hea[u] , too );
for( int i = head[u] ; i ; i = nex[i] ) {
int v = to[i];
if( v == fa[u] || v == hea[u] ) continue;
dfss( v , v );
}
} int col[MAXN]; struct node{
int l , r;
node( int L = 0 , int R = 0 ) : l(L) , r(R) { }
} T[MAXN << 2] , red( 0x3f3f3f3f , 0x3f3f3f3f ) , blu( -0x3f3f3f3f , -0x3f3f3f3f ) ;
int rec[MAXN];
// T[rt].l : if rt's heavy son is red , the value k to satisfy that this node is red
// T[rt].r : if rt's heavy son is blu , the value k to satisfy that this node is red
// b : 0 , r : 1
bool judge( int u , int k , int d ) {
// return we add d red nodes to its son if the node is red.
int B = BST :: Rank( k + 1 , BST :: root[u] ) - 1;
int R = BST :: Rank( 0x7f7f7f7f , BST :: root[u] ) - 1 - B;
return k >= R - B - d;
}
void update( int u , int& k , int d ) {
while( !judge( u , k , d ) ) ++ k;
while( judge( u , k - 1 , d ) ) -- k;
}
void work( int rt , int u ) {
if( col[u] == 0 ) {
T[rt] = red;
} else if( col[u] == 1 ) {
T[rt] = blu;
} else {
update( u , T[rt].l , 1 );
update( u , T[rt].r , -1 );
}
}
node merge( node a , node b ) {
node ret;
ret.l = min( max( b.l , a.l ) , a.r );
ret.r = min( max( b.r , a.l ) , a.r );
return ret;
}
void pushup( int rt ) {
T[rt] = merge( T[rt << 1] , T[rt << 1 | 1] );
}
node query( int rt , int l , int r , int L , int R ) {
if( l == L && r == R ) return T[rt];
int m = l + r >> 1;
if( R <= m ) return query( rt << 1 , l , m , L , R );
if( L > m ) return query( rt << 1 | 1 , m + 1 , r , L , R );
return merge( query( rt << 1 , l , m , L , m ) , query( rt << 1 | 1 , m + 1 , r , m + 1 , R ) );
}
void build( int rt , int l , int r ) {
if( l == r ) {
int u = bac[l];
work( rt , u );
if( u == top[u] && fa[u] )
BST :: insert( ( rec[u] = ( query( 1 , 1 , n , l , tig[en[u]] ) ).l ) , BST :: root[fa[u]] );
return;
}
int mid = l + r >> 1;
build( rt << 1 | 1 , mid + 1 , r ) , build( rt << 1 , l , mid );
pushup( rt );
}
void mdfy( int rt , int l , int r , int p ) {
if( l == r ) { work( rt , bac[l] ); return; }
int m = l + r >> 1;
if( p <= m ) mdfy( rt << 1 , l , m , p );
else mdfy( rt << 1 | 1 , m + 1 , r , p );
pushup( rt );
}
void modify( int x , int c ) {
col[x] = c;
while( x ) {
mdfy( 1 , 1 , n , tig[x] );
x = top[x];
if( fa[x] != 0 ) {
BST :: erase( rec[x] , BST :: root[fa[x]] );
BST :: insert( rec[x] = (query( 1 , 1 , n , tig[x] , tig[en[x]] ).l ) , BST :: root[fa[x]] );
}
x = fa[x];
}
} int main() {
BST :: init( );
cin >> n >> k;
for( int i = 1 , u , v ; i < n ; ++ i ) {
scanf("%d%d",&u,&v);
ade( u , v ) , ade( v , u );
}
for( int i = 1 ; i <= n ; ++ i ) scanf("%d",&col[i]);
dfs( 1 , 1 );
dfss( 1 , 1 );
build( 1 , 1 , n );
int q , opt , v , c; cin >> q;
while( q-- ) {
scanf("%d",&opt);
if( opt == 1 ) {
scanf("%d",&v);
printf("%d\n",( query( 1 , 1 , n , tig[v] , tig[en[top[v]]] ).l ) <= -k);
} else if( opt == 2 ) {
scanf("%d%d",&v,&c);
modify( v , c );
} else {
scanf("%d",&c);
k = c;
} }
}

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. linux与windows下文件编码问题

    注:转换操作均在Linux终端进行操作 DOS与Unix格式转换 安装工具:dos2unix.unix2dos # ubuntu apt-get install dos2unix apt-get in ...

  2. UVA-1498 Activation

    UVA-1498 DP应该是肯定的,设 f [ i ] [ j ] 表示现在对中共有 i 人,Tomato在第 j 个,出现所求情况的概率,我们可以很(简单的)艰难的列出下列方程: f[i][1] = ...

  3. vs2010中使用命令行参数

    使用VS2010增加命令参数的时候老是不起作用,后面经过研究发现,所要增加的命令参数是一个相对文件路径,而默认的工作目录里面没有该文件,所以就没有找到,需要修改工作目录,这样命令行参数才能够起作用.

  4. 查找最小生成树:普里姆算法算法(Prim)算法

    一.算法介绍 普里姆算法(Prim's algorithm),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之 ...

  5. MyBatis源码分析(五):MyBatis Cache分析

    一.Mybatis缓存介绍 在Mybatis中,它提供了一级缓存和二级缓存,默认的情况下只开启一级缓存,所以默认情况下是开启了缓存的,除非明确指定不开缓存功能.使用缓存的目的就是把数据保存在内存中,是 ...

  6. 实验6:开源控制器实践——RYU

    实验目的 能够独立部署RYU控制器 能够理解RYU控制器实现软件定义的集线器原理 能够理解RYU控制器实现软件定义的交换机原理 二.实验环境 下载虚拟机软件Oracle VisualBox或VMwar ...

  7. 像素反转 牛客网 程序员面试金典 C++ Python

    像素反转 牛客网 程序员面试金典 题目描述 有一副由NxN矩阵表示的图像,这里每个像素用一个int表示,请编写一个算法,在不占用额外内存空间的情况下(即不使用缓存矩阵),将图像顺时针旋转90度. 给定 ...

  8. sklearn模型保存与加载

    sklearn模型保存与加载 sklearn模型的保存和加载API 线性回归的模型保存加载案例 保存模型 sklearn模型的保存和加载API from sklearn.externals impor ...

  9. (五)MySQL函数

    5.1  常用函数 5.2  聚合函数(常用) 函数名称 描述 COUNT() 计数 SUM() 求和 AVG() 平均值 MAX() 最大值 MIN() 最小值 ....   ....   想查询一 ...

  10. super和this

    super注意点: 1.super调用父类的构造方法,必须在构造方法的第一个 2.super必须只能出现在子类的方法或者构造方法中 3.super和this不能同时调用构造方法 this: 代表的对象 ...