zoukankan      html  css  js  c++  java
  • BZOJ 4034: [HAOI2015]T2( 树链剖分 )

    树链剖分...子树的树链剖分序必定是一段区间 , 先记录一下就好了 

    ---------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
     
    #define rep( i , n ) for( int i = 0 ; i < n ; i++ )
    #define Rep( i , n ) for( int i = 1 ; i <= n ; ++i )
    #define clr( x , c ) memset( x , c , sizeof( x ) )
    #define REP( x ) for( edge* e = head[ x ] ; e ; e = e -> next )
     
    using namespace std;
     
    typedef long long ll;
     
    const int maxn = 100000 + 5;
     
    int n , seq[ maxn ];
     
    struct edge {
    int to;
    edge* next;
    };
     
    edge* pt , EDGE[ maxn << 1 ];
    edge* head[ maxn ];
     
    void edge_init() {
    pt = EDGE;
    clr( head , 0 );
    }
     
    void _add( int u , int v ) {
    pt -> to = v;
    pt -> next = head[ u ];
    head[ u ] = pt++;
    }
     
    #define add_edge( u , v ) _add( u , v ) , _add( v , u )
     
    int top[ maxn ] , fa[ maxn ] , size[ maxn ] , dep[ maxn ] , son[ maxn ];
    int id[ maxn ] , _id[ maxn ] , id_cnt = 0;
    int LEFT[ maxn ] , RIGHT[ maxn ];
     
    void dfs( int x ) {
    size[ x ] = 1;
    REP( x ) {
    if( e -> to == fa[ x ] ) continue;
    fa[ e -> to ] = x;
    dep[ e -> to ] = dep[ x ] + 1;
    dfs( e -> to );
    size[ x ] += size[ e -> to ];
    if( son[ x ] == -1 || size[ e -> to ] > size[ son[ x ] ] )
       son[ x ] = e -> to;
    }
    }
     
    int TOP;
    void DFS( int x ) {
    LEFT[ x ] = id[ x ] = ++id_cnt;
    _id[ id_cnt ] = x;
    top[ x ] = TOP;
    if( son[ x ] != -1 )
       DFS( son[ x ] );
    REP( x ) if( id[ e -> to ] < 0 )
       DFS( TOP = e -> to );
    RIGHT[ x ] = id_cnt;
    }
     
    void DFS_init() {
    clr( id , -1 );
    clr( son , -1 );
    dfs( dep[ 0 ] = 0 );
    DFS( TOP = 0 );
    }
     
    ll add[ maxn << 2 ] , sum[ maxn << 2 ];
     
    int op , L , R , v;
     
    #define mid( l , r ) ( l + r ) >> 1
    #define L( x ) ( x << 1 )
    #define R( x ) ( L( x ) ^ 1 )
     
    void pushdown( int x , int l , int r ) {
    if( add[ x ] ) {
       add[ L( x ) ] += add[ x ];
       add[ R( x ) ] += add[ x ];
       add[ x ] = 0;
    }
    }
    void maintain( int x , int l , int r ) {
    if( r > l ) {
    sum[ x ] = sum[ L( x ) ] + sum[ R( x ) ] + add[ x ] * ( r - l + 1 );
    } else {
       sum[ x ] += add[ x ];
       add[ x ] = 0;
    }
    }
     
    void update( int x , int l , int r ) {
    if( L <= l && r <= R ) {
    add[ x ] += v;
    } else {
    pushdown( x , l , r );
    int m = mid( l , r );
    L <= m ? update( L( x ) , l , m ) : maintain( L( x ) , l , m );
    m < R ? update( R( x ) , m + 1 , r ) : maintain( R( x ) , m + 1 , r );
    }
    maintain( x , l , r );
    }
    void U( int l , int r ) {
    L = l , R = r;
    update( 1 , 1 , n );
    }
     
    ll query( int x , int l , int r ) {
    if( L <= l && r <= R )
    return sum[ x ];
    int m = mid( l , r );
    pushdown( x , l , r );
    maintain( L( x ) , l , m );
    maintain( R( x ) , m + 1 , r );
    return ( L <= m ? query( L( x ) , l , m ) : 0 ) + ( m < R ? query( R( x ) , m + 1 , r ) : 0 );
    }
    ll Q( int l , int r ) {
    L = l , R = r;
    return query( 1 , 1 , n );
    }
     
    void build( int x , int l , int r ) {
    if( l == r ) {
    sum[ x ] = seq[ _id[ l ] ];
    } else {
    int m = mid( l , r );
    build( L( x ) , l , m );
    build( R( x ) , m + 1 , r );
    maintain( x , l , r );
    }
    }
     
    int X;
     
    ll Query() {
    ll ans = 0;
    while( top[ X ] != 0 ) {
    ans += Q( id[ top[ X ] ] , id[ X ] );
    X = fa[ top[ X ] ];
    }
    return ans + Q( id[ 0 ] , id[ X ] );
    }
     
    void modify() {
    if( op == 1 ) {
    U( id[ X ] , id[ X ] );
    } else {
    U( LEFT[ X ] , RIGHT[ X ] );
    }
    }
     
    int main() {
    freopen( "test.in" , "r" , stdin );
    int m;
    cin >> n >> m;
    rep( i , n ) scanf( "%d" , seq + i );
    edge_init();
    rep( i , n - 1 ) {
    int u , v;
    scanf( "%d%d" , &u , &v );
    u-- , v--;
    add_edge( u , v );
    }
    DFS_init();
    build( 1 , 1 , n );
    while( m-- ) {
    scanf( "%d%d" , &op , &X );
    X--;
    if( op == 3 ) {
    printf( "%lld " , Query() );
    } else {
    scanf( "%d" , &v );
    modify();
    }
    }
    return 0;
    }

      

    ----------------------------------------------------------------------------- 

    4034: [HAOI2015]T2

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 444  Solved: 181
    [Submit][Status][Discuss]

    Description

     有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个

    操作,分为三种:
    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    Input

     第一行包含两个整数 N, M 。表示点数和操作数。

    接下来一行 N 个整数,表示树中节点的初始权值。
    接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
    再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
    作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

    Output

     对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

    Sample Input

    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3

    Sample Output

    6
    9
    13

    HINT

     对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不


    会超过 10^6 。

    Source

  • 相关阅读:
    Server.MapPath()
    正斜杠(/)与反斜杠(\)总结
    ASP.NET DridView 显示行号
    Win7 64位 IIS未能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项
    DataTable中Rows.RemoveAt(i)和Rows(i).Delete的区别
    字段与属性的区别
    VS 创建assemblyinfo项目信息文件
    GridView的RowDataBound事件 获取当前行的某个数据列
    ASPxHtmlEditor上传重命名的方法
    关于ModalPopup控件不能调用CS事件代码的问题
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4572491.html
Copyright © 2011-2022 走看看