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 ; } } }}
阅读全文
0 0
- Luogu 3384 树链剖分+线段树
- [luogu]1531 线段树
- luogu 1816忠诚 线段树
- Luogu-P3372 (Lazy_tag 线段树模板)
- Luogu 3384(树链剖分)
- [DP] [1D1D优化] [线段树] [Luogu P1725] 琪露诺
- Luogu P1198 BZOJ 1012 最大数 (线段树)
- Luogu 3373(线段树标记混合下传)
- Luogu P2970 自私的放牧+线段覆盖
- 【BZOJ/Luogu】1798/P3373 [Ahoi2009]Seq 维护序列seq/【模板】线段树 2 区间加、乘线段树
- luogu p1087 FBI树
- luogu P3252 [JLOI2012]树
- LuoGu 1983 浅谈如何【车站分级】即数据架构调整加强线段树优化时空复杂度转换
- Luogu P3396普通平衡树
- Luogu-3834 (主席树模板)
- Luogu 3919(主席树)
- Luogu 1972(主席树)
- 树链剖分模板——Luogu P3384
- Redis简介
- 51nod 1304 字符串的相似度 拓展kmp
- 编写简单的消息发布器和订阅器
- Jzoj4896 兔子
- 压力测试工具
- Luogu 3384 树链剖分+线段树
- Linux shell (二)
- neo4j 如何删除所以的节点和关系
- ROC曲线面积计算
- 软件测试基础--使用测试文档
- ios-边开发边调试注意点
- NOIP模拟(11.03)T2 排列
- display属性
- spark深入理解之DAGScheduler<一>提交任务