zoukankan      html  css  js  c++  java
  • Solution -「BZOJ #3786」星系探索

    (mathcal{Description})

      Link.

      给定一棵含 (n) 个点的有根树,点有点权,支持 (q) 次操作:

    1. 询问 (u) 到根的点权和;
    2. 修改 (u) 的父亲,保证得到的图仍是树;
    3. (u) 子树内的点权增加一常数。

      (nle10^5)(qle3 imes10^5)

    (mathcal{Solution})

      ETT (Euler Tour Tree),是一种能快速处理子树移动的动态树。本质上,它将树保存作欧拉序,由于子树移动体现在欧拉序上是区间移动,那么就能使用平衡树维护序列。路径查询亦对应了一段区间内仅出现一次的结点贡献和,记每个结点第一次出现为正贡献,后一次出现为负贡献就变成了区间查询,亦能用平衡树维护。本题即 ETT 板题。

      复杂度自然是 (mathcal O((n+q)log n)) 的。

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #include <cstdio>
    #include <cassert>
    #include <cstdlib>
    
    #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
    #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
    
    typedef long long LL;
    
    const int MAXN = 1e5;
    int n, ecnt, head[MAXN + 5], w[MAXN + 5], root, st[MAXN + 5], ed[MAXN + 5];
    struct Edge { int to, nxt; } graph[MAXN + 5];
    
    inline void link( const int s, const int t ) {
        graph[++ecnt] = { t, head[s] }, head[s] = ecnt;
    }
    
    struct Treap {
        static const int MAXND = MAXN << 1;
        int node, ch[MAXND + 5][2], fa[MAXND + 5], siz[MAXND + 5], aux[MAXND + 5],
          sign[MAXND + 5], ssiz[MAXND + 5];
        LL val[MAXND + 5], sum[MAXND + 5], tag[MAXND + 5];
    
        Treap() { srand( 20120712 ); }
    
        inline int crtnd( const int v, const int s ) {
            int u = ++node;
            aux[u] = rand(), siz[u] = 1;
            sign[u] = ssiz[u] = s;
            val[u] = sum[u] = v * s;
            return u;
        }
    
        inline void pushad( const int u, const LL x ) {
            val[u] += sign[u] * x, tag[u] += x, sum[u] += x * ssiz[u];
        }
    
        inline void pushup( const int u ) {
            siz[u] = siz[ch[u][0]] + siz[ch[u][1]] + 1;
            ssiz[u] = ssiz[ch[u][0]] + ssiz[ch[u][1]] + sign[u];
            sum[u] = sum[ch[u][0]] + sum[ch[u][1]] + val[u];
        }
    
        inline void pushdn( const int u ) {
            if ( tag[u] ) {
                if ( ch[u][0] ) pushad( ch[u][0], tag[u] );
                if ( ch[u][1] ) pushad( ch[u][1], tag[u] );
                tag[u] = 0;
            }
        }
    
        inline int merge( const int u, const int v ) {
            if ( !u || !v ) return u | v;
            pushdn( u ), pushdn( v );
            if ( aux[u] < aux[v] ) {
                ch[u][1] = merge( ch[u][1], v );
                if ( ch[u][1] ) fa[ch[u][1]] = u;
                return pushup( u ), u;
            } else {
                ch[v][0] = merge( u, ch[v][0] );
                if ( ch[v][0] ) fa[ch[v][0]] = v;
                return pushup( v ), v;
            }
        }
    
        inline void rsplit( const int u, const int k, int& x, int& y ) {
            if ( !u ) return void( x = y = 0 );
            fa[u] = 0, pushdn( u );
            if ( siz[ch[u][0]] >= k ) {
                y = u, rsplit( ch[u][0], k, x, ch[y][0] );
                if ( ch[y][0] ) fa[ch[y][0]] = y;
            } else {
                x = u, rsplit( ch[u][1], k - siz[ch[u][0]] - 1, ch[x][1], y );
                if ( ch[x][1] ) fa[ch[x][1]] = x;
            }
            pushup( u );
        }
    
        inline int rank( int u ) {
            int ret = siz[ch[u][0]] + 1;
            while ( fa[u] ) {
                if ( ch[fa[u]][1] == u ) ret += siz[ch[fa[u]][0]] + 1;
                u = fa[u];
            }
            return ret;
        }
    } trp;
    
    inline void init( const int u ) {
        root = trp.merge( root, st[u] = trp.crtnd( w[u], 1 ) );
        for ( int i = head[u]; i; i = graph[i].nxt ) init( graph[i].to );
        root = trp.merge( root, ed[u] = trp.crtnd( w[u], -1 ) );
    }
    
    inline LL query( const int u ) {
        int l = trp.rank( st[1] ), r = trp.rank( st[u] ), x, y, z;
        assert( l == 1 );
        trp.rsplit( root, l - 1, x, y ), trp.rsplit( y, r - l + 1, y, z );
        LL ret = trp.sum[y];
        root = trp.merge( x, trp.merge( y, z ) );
        return ret;
    }
    
    inline void change( const int u, const int p ) {
        int l = trp.rank( st[u] ), r = trp.rank( ed[u] ), tar = trp.rank( st[p] ),
          x, y, z, m;
        if ( tar < l ) {
            trp.rsplit( root, tar, x, y );
            trp.rsplit( y, l - tar - 1, y, z );
            trp.rsplit( z, r - l + 1, z, m );
        } else {
            trp.rsplit( root, l - 1, x, y );
            trp.rsplit( y, r - l + 1, y, z );
            trp.rsplit( z, tar - r, z, m );
        }
        root = trp.merge( trp.merge( x, z ), trp.merge( y, m ) );
    }
    
    inline void update( const int u, const int p ) {
        int l = trp.rank( st[u] ), r = trp.rank( ed[u] ), x, y, z;
        trp.rsplit( root, l - 1, x, y ), trp.rsplit( y, r - l + 1, y, z );
        trp.pushad( y, p ), root = trp.merge( x, trp.merge( y, z ) );
    }
    
    int main() {
        scanf( "%d", &n );
        for ( int i = 2, t; i <= n; ++i ) scanf( "%d", &t ), link( t, i );
        rep ( i, 1, n ) scanf( "%d", &w[i] );
    
        init( 1 );
    
        char op[5]; int q, a, b;
        for ( scanf( "%d", &q ); q--; ) {
            scanf( "%s %d", op, &a );
            if ( op[0] == 'Q' ) printf( "%lld
    ", query( a ) );
            else if ( op[0] == 'C' ) scanf( "%d", &b ), change( a, b );
            else scanf( "%d", &b ), update( a, b );
        }
        return 0;
    }
    
    
  • 相关阅读:
    web网页测试用例(非常实用)
    怎么做web接口测试
    我的周记13——”离开,是为了更好的回来"
    Lambda 表达式常用函数
    IEnumberable<T>接口
    Linq的学习
    未能加载文件或程序集“Newtonsoft.Json”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。
    拉姆达表达式的笔记
    注册今日头条
    爬取百思不得姐的段子
  • 原文地址:https://www.cnblogs.com/rainybunny/p/14987996.html
Copyright © 2011-2022 走看看