Luogu 3384 树链剖分+线段树

来源:互联网 发布:暖气片不热 知乎 编辑:程序博客网 时间:2024/06/18 02:54

大家好我是一个树链剖分写抽了的人

Description:

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

题解:

直接上链剖,一定要记住跳的时候时判dep [top [u]]和dep [top [v]]。

# include <bits/stdc++.h>inline int read ( )  {# define SIZE 2000005    static std :: streambuf *fb ( std :: cin.rdbuf ( ) ) ;    static char buf [SIZE], *ss ( 0 ), *tt ( 0 ) ;# define pick( )  ( (ss == tt) ? ( tt = buf + fb -> sgetn ( ss = buf, SIZE ), ((ss == tt) ? -1 : *(ss ++)) ) :*(ss ++) )    register int x, c ;    bool opt ( 1 ) ;    while ( ! isdigit ( c = pick ( ) ) && ( c ^ -1 ) && ( c ^ 45 ) ) ;    if ( c == 45 )  c = pick ( ), opt = 0 ;    for ( x = -48 + c ; isdigit ( c = pick ( ) ) ; ( x *= 10 ) += c - 48 ) ;    return opt ? x : -x ;# undef pick}int Mod ;# define fix( x )  {\    while ( x >= Mod )  x -= Mod ;\    while ( x < 0 )  x += Mod ;\}# define N 100010struct node  {    int sum ;    int lazy ;    bool flag ;    node *ls, *rs ;    inline void update ( )  {        sum = ls -> sum + rs -> sum ;        fix ( sum ) ;    }    inline void pushdown ( int l, int r )  {        if ( flag )  {            ls -> flag = rs -> flag = 1 ;            int mid = ( l + r ) >> 1 ;            ls -> sum += 1LL * ( mid - l + 1 ) * lazy % Mod ;            rs -> sum += 1LL * ( r - mid ) * lazy % Mod ;            ls -> lazy += lazy ;            rs -> lazy += lazy ;            fix ( ls -> lazy ) ;            fix ( rs -> lazy ) ;            flag = 0 ;            lazy = 0 ;        }    }}  pool [N << 2], *pt = pool, *root ;struct edge  {    int to ; edge* nxt ;} ;struct Graph  {    edge g [N << 1], *head [N] ;    Graph ( )  {  memset ( head, 0, sizeof head ) ;  }    inline void add_edge ( int u, int v )  {        static edge* NewEdge ( g ) ;        *( ++ NewEdge ) = ( edge ) {  v, head [u]  } ; head [u] = NewEdge ;    }    inline void add_double_edge ( int u, int v )  {        add_edge ( u, v ), add_edge ( v, u ) ;    }    inline edge*& operator [] ( const int& u )  {  return head [u] ;  }} G ;int n ;int a [N] ;int top [N], dfn [N], out [N], siz [N], son [N], fa [N], dep [N], seq [N], idx ;# undef Ninline void Dfs1 ( int u, int f )  {    siz [u] = 1 ;    fa [u] = f ;    for ( edge* it = G [u] ; it ; it = it -> nxt )  {        int& v = it -> to ;        if ( v ^ f )  {            dep [v] = dep [u] + 1 ;            Dfs1 ( v, u ) ;            siz [u] += siz [v] ;            if ( siz [u] == 0 || siz [son [u]] < siz [v] )  {                son [u] = v ;            }        }    }}inline void Dfs2 ( int u, int tp )  {    top [u] = tp, dfn [u] = ++ idx, seq [idx] = u ;    if ( son [u] )  Dfs2 ( son [u], tp ) ;    for ( edge* it = G [u] ; it ; it = it -> nxt )  {        int& v = it -> to ;        if ( ( v ^ fa [u] ) && ( v ^ son [u] ) )  {            Dfs2 ( v, v ) ;        }    }    out [u] = idx ;}inline node* build ( int lf, int rg )  {    node* nd = pt ++ ;    nd -> sum = 0, nd -> flag = 0, nd -> lazy = 0 ;    if ( lf == rg )  {        nd -> sum = a [seq [lf]] ;        return nd ;    }    int mid = ( lf + rg ) >> 1 ;    nd -> ls = build ( lf, mid ) ;    nd -> rs = build ( mid + 1, rg ) ;    nd -> update ( ) ;    return nd ;}inline void Modify ( node*& nd, int lf, int rg, int L, int R, int delta )  {    if ( L <= lf && rg <= R )  {        nd -> sum += 1LL * ( rg - lf + 1 ) * delta % Mod ;        nd -> flag = 1 ;        nd -> lazy += delta ;        fix ( nd -> lazy ) ;        return ;    }    nd -> pushdown ( lf, rg ) ;    int mid = ( lf + rg ) >> 1 ;    if ( L <= mid )  Modify ( nd -> ls, lf, mid, L, R, delta ) ;    if ( R > mid )  Modify ( nd -> rs, mid + 1, rg, L, R, delta ) ;    nd -> update ( ) ;}inline int Query ( node*& nd, int lf, int rg, int L, int R )  {    if ( L <= lf && rg <= R )  {        return nd -> sum ;    }    nd -> pushdown ( lf, rg ) ;    int mid = ( lf + rg ) >> 1 ;    int rt ( 0 ) ;    if ( L <= mid )  rt = Query ( nd -> ls, lf, mid, L, R ) ;    if ( R > mid )  rt += Query ( nd -> rs, mid + 1, rg, L, R ) ;    fix ( rt ) ;    return rt ;}inline void Modify ( int u, int v, int val )  {    while ( top [u] ^ top [v] )  {        if ( dep [top [u]] < dep [top [v]] )  u ^= v ^= u ^= v ;        Modify ( root, 1, n, dfn [top [u]], dfn [u], val ) ;        u = fa [top [u]] ;    }    if ( dep [u] < dep [v] )  u ^= v ^= u ^= v ;    Modify ( root, 1, n, dfn [v], dfn [u], val ) ;}inline int Query ( int u, int v )  {    int rt ( 0 ) ;    while ( top [u] ^ top [v] )  {        if ( dep [top [u]] < dep [top [v]] )  u ^= v ^= u ^= v ;        rt += Query ( root, 1, n, dfn [top [u]], dfn [u] ) ;        fix ( rt ) ;        u = fa [top [u]] ;    }    if ( dep [u] < dep [v] )  u ^= v ^= u ^= v ;    rt += Query ( root, 1, n, dfn [v], dfn [u] ) ;    fix ( rt ) ;    return rt ;}int main ( )  {    std :: ios :: sync_with_stdio ( 0 ) ;    std :: cin.tie ( 0 ) ;    :: n = read ( ) ;    int m ( read ( ) ), s ( read ( ) ) ;    Mod = read ( ) ;    for ( int i = 1 ; i <= n ; ++ i )  a [i] = read ( ) ;    for ( int i = 1 ; i < n ; ++ i )  {        G.add_double_edge ( read ( ), read ( ) ) ;    }    Dfs1 ( s, 0 ) ;    Dfs2 ( s, s ) ;    root = build ( 1, n ) ;    while ( m -- )  {        int opt ( read ( ) ) ;        switch ( opt )  {            case 1 :  {                int u ( read ( ) ), v ( read ( ) ), val ( read ( ) ) ;                fix ( val ) ;                Modify ( u, v, val ) ;                break ;            }            case 2 :  {                int u ( read ( ) ), v ( read ( ) ) ;                printf ( "%d\n", Query ( u, v ) ) ;                break ;            }            case 3 :  {                int x ( read ( ) ), val ( read ( ) ) ;                fix ( val ) ;                Modify ( root, 1, n, dfn [x], out [x], val ) ;                break ;            }            case 4 :  {                int x ( read ( ) ) ;                printf ( "%d\n", Query ( root, 1, n, dfn [x], out [x] ) ) ;                break ;            }        }    }}
原创粉丝点击