codevs4927 线段树练习5(线段树)

来源:互联网 发布:阿里云网站官方网站 编辑:程序博客网 时间:2024/06/08 01:25

题目

描述

有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]的最小值

输入

第一行两个整数n,m,第二行n个整数表示这n个数的初始值
接下来m行操作,同题目描述

输出

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

样例输入

10 63 9 2 8 1 7 5 0 4 6add 4 9 4set 2 6 2add 3 8 2sum 2 10max 1 7min 3 6

样例输出

49114

数据范围及提示

10%: 1<n,m10
30%: 1<n,m10000
100%: 1<n,m100000
保证中间结果在long long(C/C++)、int64(pascal)范围内

解题思路

线段树中每个节点有两个标记:set和add,分别表示重置和区间加。定义一个节点同时存在两个标记时,先下放set标记,再下放加标记,那么当我们进行重置操作时,只需要将当前节点的加标记清零即可。

Code

#include<cstdio>#include<algorithm>#define lid id<<1#define rid id<<1|1#define mid ((tr[id].l+tr[id].r)>>1)#define len(id) (tr[id].r-tr[id].l+1)using namespace std;typedef long long LL;const LL INF = 1e17;const int N = 100005;int n, m, ql, qr;LL a[N], x;char opt[4];struct seg_tree{    int l, r;    LL sum, mx, mn;    LL set, add;    void init(){        l = r = 0;        sum = 0, mx = -INF, mn = INF;        add = 0, set = INF;    }}tr[N<<2];inline void pushup(int id){    tr[id].sum = tr[lid].sum + tr[rid].sum;    tr[id].mx = max(tr[lid].mx, tr[rid].mx);    tr[id].mn = min(tr[lid].mn, tr[rid].mn);}inline void pushdown(int id){    if(tr[id].l == tr[id].r)    return;    if(tr[id].set != INF){        LL t = tr[id].set;        tr[lid].set = t;        tr[lid].add = 0;        tr[lid].sum = t * len(lid);        tr[lid].mx = tr[lid].mn = t;        tr[rid].set = t;        tr[rid].add = 0;        tr[rid].sum = t * len(rid);        tr[rid].mx = tr[rid].mn = t;        tr[id].set = INF;    }    if(tr[id].add){        LL t = tr[id].add;        tr[lid].add += t;        tr[lid].sum += t * len(lid);        tr[lid].mx += t;        tr[lid].mn += t;        tr[rid].add += t;        tr[rid].sum += t * len(rid);        tr[rid].mx += t;        tr[rid].mn += t;        tr[id].add = 0;    }}void build(int id, int l, int r){    tr[id].init();    tr[id].l = l, tr[id].r = r;    if(tr[id].l == tr[id].r){        tr[id].sum = tr[id].mx = tr[id].mn = a[l];        return;    }    build(lid, l, mid);    build(rid, mid+1, r);    pushup(id);}void modify(int id, int l, int r, LL val, int kind){    pushdown(id);    if(tr[id].l == l && tr[id].r == r){        if(kind == 0){            tr[id].add += val;            tr[id].sum += val * len(id);            tr[id].mx += val, tr[id].mn += val;        }        else{            tr[id].set = val;            tr[id].add = 0;            tr[id].sum = val * len(id);            tr[id].mx = tr[id].mn = val;        }        return;    }    if(r <= mid)    modify(lid, l, r, val, kind);    else if(l > mid)    modify(rid, l, r, val, kind);    else    modify(lid, l, mid, val, kind), modify(rid, mid+1, r, val, kind);    pushup(id);}LL query(int id, int l, int r, int kind){    pushdown(id);    if(tr[id].l == l && tr[id].r == r){        if(kind == 0)   return tr[id].sum;        if(kind == 1)   return tr[id].mx;        if(kind == 2)   return tr[id].mn;    }    if(r <= mid)    return query(lid, l, r, kind);    else if(l > mid)    return query(rid, l, r, kind);    else{        if(kind == 0)   return query(lid, l, mid, kind) + query(rid, mid+1, r, kind);        if(kind == 1)   return max(query(lid, l, mid, kind), query(rid, mid+1, r, kind));        if(kind == 2)   return min(query(lid, l, mid, kind), query(rid, mid+1, r, kind));    }}int main(){    scanf("%d%d", &n, &m);    for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);    build(1, 1, n);    while(m--){        scanf("%s%d%d", opt, &ql, &qr);        if(opt[0] == 'a'){            scanf("%lld", &x);            modify(1, ql, qr, x, 0);        }        else if(opt[1] == 'e'){            scanf("%lld", &x);            modify(1, ql, qr, x, 1);        }        else if(opt[0] == 's')            printf("%lld\n", query(1, ql, qr, 0));        else if(opt[1] == 'a')            printf("%lld\n", query(1, ql, qr, 1));        else if(opt[1] == 'i')            printf("%lld\n", query(1, ql, qr, 2));    }    return 0;}
原创粉丝点击