zoukankan      html  css  js  c++  java
  • HDU 1698 Just a Hook 线段树 区间更新

      题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1698

      题目描述: 区间更新, 最后求出1 ~ n 之和  

      解题思路: 这里涉及到区间更新, 这也是我第一次写区间更新, 以前都是单点更新, 回溯就可以了, 如果将区间更新化成区间长度的单点更新, 复杂度会很大, 所以这里使用了懒惰标记的方法来解决这个问题。 懒惰标记, 顾名思义就是放着不管, 简单来说就是区间更新是不向下更新, 先打一个标记, 等下次更新或者查询的时候才向下更新一步, (同理打懒惰标记)。 

      代码: 

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <map>
    #include <cstring>
    #include <iterator>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <deque>
    #include <map>
    
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    using namespace std;
    int cases;
    const int maxn = 1e5+10;
    int n;
    int tree[maxn<<2];
    int col[maxn<<2];
    
    void Pushup( int rt ) {
        tree[rt] = tree[rt<<1] + tree[rt<<1|1];
    }
    
    void Pushdown( int rt, int m ) {
        if( col[rt] ) {
            col[rt<<1] = col[rt<<1|1] = col[rt];
            tree[rt<<1] = (m-(m >> 1)) * col[rt];
            tree[rt<<1|1] = (m >> 1) * col[rt];
            col[rt] = 0;
        }
    }
    void build( int l, int r, int rt ) {
        col[rt] = 0;
        tree[rt] = 1;
        if( l == r ) return;
        int m = (l + r) >> 1;
        build( lson );
        build( rson );
        Pushup(rt);
    }
    
    void Update( int L, int R, int x, int l, int r, int rt ) {
        if( L <= l && r <= R ) {
            col[rt] = x;
            tree[rt] = x * (r-l+1);
            return;
        }
        Pushdown( rt, r-l+1 );
        int m = (l + r) >> 1;
        if( L <= m ) Update( L, R, x, lson );
        if( R > m ) Update( L, R, x, rson );
        Pushup( rt );
        return;
    }
    
    void debug() {
        for( int i = 1; i <= 40; i++ ) {
            cout << tree[i] << " ";
        }
        cout << endl;
        for( int i = 1; i <= 40; i++ ) {
            cout << col[i] << " ";
        }
        cout << endl;
    }
    
    int main() {
        int t;
        scanf( "%d", &t );
        cases = 1;
        while( t-- ) {
            scanf( "%d", &n );
            build( 1, n, 1 );
            debug();
            int m;
            scanf( "%d", &m );
            for( int i = 0; i < m; i++ ) {
                int a, b, c;
                scanf( "%d%d%d", &a, &b, &c );
                Update( a, b, c, 1, n, 1 );
                debug();
            }
    //        debug();
    //        cout << "===" << endl;
            printf( "Case %d: The total value of the hook is %d.
    ", cases++, tree[1] );
        }
        return 0;
    }
    View Code

      思考: 这个懒惰标记很巧妙, 我一时间没有弄懂, 今天上午把函数调用过程全部写出来才感觉稍微有一点明白原理了,每次update函数就是先判定是否当前判定区间在给定区间中, 如果在,给该区间的根节点打上懒惰标记,(   本题中懒惰标记就是钩子的上色), 只更新当期根节点的值, 如果不在, {如果当前根节点标记有懒惰标记, 将懒惰标记传给两个儿子并且取消当前根节点的懒惰标记, 当然同时只更新两个儿子的值如果当前根节点没有懒惰标记, 什么也不做}, 然后就是分治左右区间, 在函数回溯的时候更新区间和。

      想了好久, 现在脑子还是有点儿乱, 遇到不同的题再想吧

  • 相关阅读:
    .NET 4.5 is an in-place replacement for .NET 4.0
    python Argparse模块的使用
    linux的fork(), vfork()区别
    Linux 的 strace 命令
    NTFS系统的ADS交换数据流
    Git和.gitignore
    GIT常用命令
    OSChina码云试用
    tcpdump用法
    linux网卡混杂模式
  • 原文地址:https://www.cnblogs.com/FriskyPuppy/p/7298402.html
Copyright © 2011-2022 走看看