• codevs 4927 线段树练习5


                    codevs 4927  线段树练习5

    题目描述 Description

    有n个数和5种操作

    add a b c:把区间[a,b]内的所有数都增加c

    set a b c:把区间[a,b]内的所有数都设为c

    sum a b:查询区间[a,b]的区间和

    max a b:查询区间[a,b]的最大值

    min a b:查询区间[a,b]的最小值

    输入描述 Input Description

    第一行两个整数n,m,第二行n个整数表示这n个数的初始值

    接下来m行操作,同题目描述

    输出描述 Output Description

    对于所有的sum、max、min询问,一行输出一个答案

    样例输入 Sample Input

    10 6

    3 9 2 8 1 7 5 0 4 6

    add 4 9 4

    set 2 6 2

    add 3 8 2

    sum 2 10

    max 1 7

    min 3 6

    样例输出 Sample Output

    49

    11

    4

    数据范围及提示 Data Size & Hint

    10%:1<n,m<=10

    30%:1<n,m<=10000

    100%:1<n,m<=100000

    保证中间结果在long long(C/C++)、int64(pascal)范围内

    考察算法:线段树双重标记

    思路:线段树区间加法和区间赋值

    先赋值,后加法(赋值后,之前的加法失效)

    注意:有将区间内的数都赋为0的情况

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define N 100001
    #define LL long long
    using namespace std;
    int n, m, x, y;
    LL z;
    string s;
    bool sign;
    struct nond {
        int ll, rr;
        LL flag1, flag2, sum;
        LL minn, maxn;
    }tree[4*N];
    void up(int now) {
        tree[now].sum = tree[now*2].sum+tree[now*2+1].sum;
        tree[now].maxn = max(tree[now*2].maxn, tree[now*2+1].maxn);
        tree[now].minn = min(tree[now*2].minn, tree[now*2+1].minn);
    }
    void down(int now) {
        if(tree[now].flag2!=-1) {
            tree[now*2].flag1 = tree[now*2+1].flag1 = 0;
            tree[now*2].flag2 = tree[now].flag2;
            tree[now*2+1].flag2 = tree[now].flag2;
            tree[now*2].sum = (tree[now*2].rr-tree[now*2].ll+1) * tree[now].flag2;
            tree[now*2+1].sum = (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].flag2;
            tree[now*2].maxn = tree[now].flag2;
            tree[now*2+1].maxn = tree[now].flag2;
            tree[now*2].minn = tree[now].flag2;
            tree[now*2+1].minn = tree[now].flag2;
            tree[now].flag2 = -1;
        }
        if(tree[now].flag1) {
            tree[now*2].flag1 += tree[now].flag1;
            tree[now*2+1].flag1 += tree[now].flag1;
            tree[now*2].sum += (tree[now*2].rr-tree[now*2].ll+1) * tree[now].flag1;
            tree[now*2+1].sum += (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].flag1;
            tree[now*2].maxn += tree[now].flag1;
            tree[now*2+1].maxn += tree[now].flag1;
            tree[now*2].minn += tree[now].flag1;
            tree[now*2+1].minn += tree[now].flag1;
            tree[now].flag1 = 0;
        }
        return ;
    }
    void build(int now, int l, int r) {
        tree[now].ll = l; tree[now].rr = r;
        tree[now].flag1 = 0; tree[now].flag2 = -1;
        if(l == r) {
            scanf("%lld", &tree[now].sum);
            tree[now].maxn = tree[now].sum;
            tree[now].minn = tree[now].sum;
            return ;
        }
        int mid = (l+r) / 2;
        build(now*2, l, mid);
        build(now*2+1, mid+1, r);
        up(now);
    }
    void add(int now, int l, int r) {
        if(tree[now].ll==l && tree[now].rr==r) {
            tree[now].flag1 += z;
            tree[now].sum += (tree[now].rr-tree[now].ll+1) * z;
            tree[now].maxn += z;
            tree[now].minn += z;
            return ;
        }
        if(tree[now].flag2!=-1 || tree[now].flag1) down(now);
        int mid = (tree[now].ll+tree[now].rr) / 2;
        if(l<=mid && mid<r) add(now*2, l, mid), add(now*2+1, mid+1, r);
        else if(r<=mid) add(now*2, l, r);
                else add(now*2+1, l, r);
        up(now);
    }
    void set(int now, int l, int r) {
        if(tree[now].ll==l && tree[now].rr==r) {
            tree[now].flag2 = z; tree[now].flag1 = 0;
            tree[now].sum = (tree[now].rr-tree[now].ll+1) * z;
            tree[now].maxn = tree[now].minn = z;
            return ;
        }
        if(tree[now].flag2!=-1 || tree[now].flag1) down(now);
        int mid = (tree[now].ll+tree[now].rr) / 2;
        if(l<=mid && mid<r) set(now*2, l, mid), set(now*2+1, mid+1, r);
        else if(r<=mid) set(now*2, l, r);
                else set(now*2+1, l, r);
        up(now);
    }
    LL query(int now, int l, int r) {
        if(tree[now].ll==l && tree[now].rr==r) return tree[now].sum;
        if(tree[now].flag2!=-1 || tree[now].flag1) down(now);
        int mid = (tree[now].ll+tree[now].rr) / 2;
        if(l<=mid && mid<r) return query(now*2, l, mid) + query(now*2+1, mid+1, r);
        else if(r<=mid) return query(now*2, l, r);
                else return query(now*2+1, l, r);
    }
    LL little(int now, int l, int r) {
        if(tree[now].ll==l && tree[now].rr==r) return tree[now].minn;
        if(tree[now].flag2!=-1 || tree[now].flag1) down(now);
        int mid = (tree[now].ll+tree[now].rr) / 2;
        if(l<=mid && mid<r) return min(little(now*2, l, mid), little(now*2+1, mid+1, r));
        else if(r<=mid) return little(now*2, l, r);
                else return little(now*2+1, l, r);
    }
    LL large(int now, int l, int r) {
        if(tree[now].ll==l && tree[now].rr==r) return tree[now].maxn;
        if(tree[now].flag2!=-1 || tree[now].flag1) down(now);
        int mid = (tree[now].ll+tree[now].rr) / 2;
        if(l<=mid && mid<r) return max(large(now*2, l, mid), large(now*2+1, mid+1, r));
        else if(r<=mid) return large(now*2, l, r);
                else return large(now*2+1, l, r);
    }
    int main() {
        scanf("%d%d", &n, &m);
        build(1, 1, n);
        for(int i = 1; i <= m; i++) {
            cin >> s;
            if(s[1] == 'd') { scanf("%d%d%lld", &x, &y, &z); add(1, x, y); continue; }
            if(s[1] == 'e') { scanf("%d%d%lld", &x, &y, &z); set(1, x, y); continue; }
            if(s[1] == 'u') { scanf("%d%d", &x, &y); printf("%lld
    ", query(1, x, y)); continue; }
            if(s[1] == 'i') { scanf("%d%d", &x, &y); printf("%lld
    ", little(1, x, y)); continue; }
            if(s[1] == 'a') { scanf("%d%d", &x, &y); printf("%lld
    ", large(1, x, y)); continue; }
        }
        return 0;
    }
  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/v-vip/p/8537425.html
Copyright © 2020-2023  润新知