zoukankan      html  css  js  c++  java
  • poj3439 A Simple Problem with Integers 延迟更新的线段树

    思路:使用线段树,并且采用延迟标记的方法使更新操作的复杂度控制在O(logn)。这里采用数组的方法存储二叉树,可以省下两个指针的空间,但代码变得不是很直观,而且容易犯错。

    另外此题中数据可能超过32位,故使用long long类型存储(POJ平台不能采用__int64,具体原因参见这里),同时使用%lld输出。另外,直接使用scanf读入一个字符的方法会读入空白字符,这里使用scanf("%1s",c);实现。注意因为%s会在输入字符串的末尾加上终止符'\0',故c至少是一个长度为2的数组。

    6596kB 600ms 3338 B

    #include <stdio.h>
    struct InTree{
        int l,u;
        long long v;//使用long long 和输入输入的%lld来保证数据超过32位仍能正常运行
        long long add;//add为延迟标记,标识它的子结点中的每个元素需要增加add
    };
    InTree tree[3*100000];
    //最多有2N-1个节点,最底层最多有N个节点,所以最多占用3N-2个位置。使用tree数组的1~3N-1位置。
    
    //A是输入的数据,i是当前节点在tree数组中的位置,l和u是上下界
    void BuildInTree(int *A,int i,int low, int upp){
        tree[i].add = 0;
        if(low==upp){
            tree[i].l = tree[i].u = low;
            tree[i].v = A[low];
            return;
        }
        else{
            tree[i].l = low;
            tree[i].u = upp;
            BuildInTree(A,2*i,low,(low+upp)/2);//左子树的位置为2*i
            BuildInTree(A,2*i+1,(low+upp)/2+1,upp);//右子树的位置为2*i+1
            tree[i].v = tree[2*i].v + tree[2*i+1].v;
        }
    }
    
    //更新l到u区间的叶节点值加上v,tree[i]为当前节点,在这里采用延迟标记的方法
    void Update(int i,int low, int upp, long long v){
        if(low <= tree[i].l && tree[i].u <= upp){
            tree[i].v += (tree[i].u-tree[i].l+1)*v;//查询到本节点,更新数据
            tree[i].add += v;//更新标记
        }
        else{
        //更新tree[i]的左右的左右子树的标记
            if(tree[i].add !=0){
                //先把标记应用到子结点,再更新子结点的标记
                tree[2*i].v += (tree[2*i].u-tree[2*i].l+1)* tree[i].add;
                tree[2*i].add += tree[i].add;
                tree[2*i+1].v += (tree[2*i+1].u-tree[2*i+1].l+1)* tree[i].add;
                tree[2*i+1].add += tree[i].add;
                tree[i].add = 0;//将本节点的标记置0
            }
    
            if(low<=(tree[i].l+tree[i].u)/2){
                Update(2*i,low,upp,v);
            }
            if(upp>=(tree[i].l+tree[i].u)/2+1){
                Update(2*i+1,low,upp,v);
            }
            tree[i].v = tree[2*i].v + tree[2*i+1].v;
        }
    }
    
    //查询l到u之间的数据和,tree[i]为当前节点
    long long Query(int i,int low, int upp){
        if(low <= tree[i].l && tree[i].u <= upp){
            return tree[i].v;
        }
        else{
        //更新tree[i]的左右的左右子树的标记
            if(tree[i].add !=0){
                //先把标记应用到子结点,再更新子结点的标记
                tree[2*i].v += (tree[2*i].u-tree[2*i].l+1)* tree[i].add;
                tree[2*i].add += tree[i].add;
                tree[2*i+1].v += (tree[2*i+1].u-tree[2*i+1].l+1)* tree[i].add;
                tree[2*i+1].add += tree[i].add;
    
                tree[i].add = 0;//将本节点的标记置0
            }
            long long val = 0;
            if(low<=(tree[i].l+tree[i].u)/2){
                val += Query(2*i,low,upp);
            }
            if(upp>=(tree[i].l+tree[i].u)/2+1){
                val += Query(2*i+1,low,upp);
            }
            return val;
        }
    }
    int main(){
        int N,Q;
        scanf("%d %d", &N, &Q);
        int *A = new int[N+1];//只使用1~N的区间
        for(int i=1;i<=N;i++)scanf("%d", A+i);
        BuildInTree(A,1,1,N);
    
        char c[2];
        int l,u;
        long long add;
    
        for(int i=0;i<Q;i++){
            scanf("%1s",c);//读入一个非空白的字符,注意留空间给%s末尾的'\0'
            if(c[0]=='Q'){
                scanf("%d %d",&l,&u);
                printf("%lld\n",Query(1,l,u));
            }
            else if(c[0]=='C'){
                scanf("%d %d %lld",&l,&u,&add);
                Update(1,l,u,add);
            }
        }
        return 0;
    }
    3439:A Simple Problem with Integers
    查看 提交 统计 提示 提问
    时间限制: 5000ms 内存限制: 65536kB
    描述
    You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.


    输入
    The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
    The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
    Each of the next Q lines represents an operation.
    "C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
    "Q a b" means querying the sum of Aa, Aa+1, ... , Ab.


    输出
    You need to answer all Q commands in order. One answer in a line.


    样例输入
    10 5
    1 2 3 4 5 6 7 8 9 10
    Q 4 4
    Q 1 10
    Q 2 4
    C 3 6 3
    Q 2 4
    样例输出
    4
    55
    9
    15


  • 相关阅读:
    java:transient是什么,有什么作用
    如何阅读java源码
    java里面list是引用的好例子
    sort给文件按照大小排序
    HBase的rowkey排序和scan输出顺序
    记录一次事故——idea,sbt,scala
    一个简单的synchronized多线程问题、梳理与思考
    Android TextView文字描边的实现!!
    android中include标签的使用
    layout_weight 的解释及使用
  • 原文地址:https://www.cnblogs.com/zhuyuanhao/p/3262861.html
Copyright © 2011-2022 走看看