CF1208H Red Blue Tree

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;
        }

    }
}

原文地址:https://www.cnblogs.com/yijan/p/cf1208h.html

时间: 2024-08-02 23:43:36

CF1208H Red Blue Tree的相关文章

BNUOJ 26229 Red/Blue Spanning Tree

Red/Blue Spanning Tree Time Limit: 2000ms Memory Limit: 131072KB This problem will be judged on HDU. Original ID: 426364-bit integer IO format: %I64d      Java class name: Main Given an undirected, unweighted, connected graph, where each edge is colo

HDU 4263(Red/Blue Spanning Tree-取边贪心)

Red/Blue Spanning Tree Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 979    Accepted Submission(s): 368 Problem Description Given an undirected, unweighted, connected graph, where each edg

红黑树(Red Black Tree)

介绍另一种平衡二叉树:红黑树(Red Black Tree),红黑树由Rudolf Bayer于1972年发明,当时被称为平衡二叉B树(symmetric binary B-trees),1978年被Leonidas J. Guibas 和 Robert Sedgewick改成一个比较摩登的名字:红黑树. 红黑树和之前所讲的AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能.自从红黑树出来后,AVL树就被放到了博物馆里,据说是红黑树有更好的效率,更高

数据结构 - 红黑树(Red Black Tree)插入详解与实现(Java)

最终还是决定把红黑树的篇章一分为二,插入操作一篇,删除操作一篇,因为合在一起写篇幅实在太长了,写起来都觉得累,何况是阅读并理解的读者. 红黑树删除操作请参考 数据结构 - 红黑树(Red Black Tree)删除详解与实现(Java) 现在网络上最不缺的就是对某个知识点的讲解博文,各种花样标题百出,更有类似"一文讲懂xxx","史上最简单的xxx讲解","xxx看了还不懂你打我"之类云云.其中也不乏有些理论甚至是举例都雷同的两篇不同文章,至于作

1208 H. Red Blud Tree

1208 H. Red Blud Tree 题意: 给定一棵树和常数\(k\),每个结点的颜色为蓝色或红色,叶子结点颜色是给定的,内部结点的颜色为蓝色当且仅当蓝色儿子数\(-\)红色儿子数\(\geq k\).要求支持三种查询: 1.输出某个结点的颜色. 2.修改某个叶子结点的颜色 3.修改\(k\)的值. 题解: 先考虑没有操作2的情况.那么相当于查询某个结点在\(k\)为某个值的时候的颜色.当\(k=-\infty\)时,所有内部结点都为蓝色.对每个内部结点,当\(k\)增大到某个值之后,它

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 the vertices, of them are red, while the others are black. The root of the tree is vertex 1 and it's a red vertex.Let's define the cost of a red verte

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 the vertices, m of them are red, while the others are black. The root of the tree is vertex 1 and it’s a red vertex. Let’s define the cost of a red ve

计蒜客 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 the nodes are colored red, the rest are black. You would like to choose a subset of nodes such that there is no node in your subset which is an ancest

RBTree(RED,BLACK)Tree

红黑树是一棵二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是Red或Black.通过对任何一条从根到叶子简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似于平衡. 红黑树是满足下面红黑性质的二叉搜索树 每个节点,不是红色就是黑色的 根节点是黑色的 如果一个节点是红色的,则它的两个子节点是黑色的(没有连续的红节点) 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点.(每条路径的黑色节点的数量相等) 每个叶子节点都是黑色的(这里的叶