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\n", query(1, x, y)); continue; }
        if(s[1] == 'i') { scanf("%d%d", &x, &y); printf("%lld\n", little(1, x, y)); continue; }
        if(s[1] == 'a') { scanf("%d%d", &x, &y); printf("%lld\n", large(1, x, y)); continue; }
    }
    return 0;
}

 

posted @ 2018-03-10 09:38  落云小师妹  阅读(171)  评论(0编辑  收藏  举报