CodeVS4927 线段树5 区间修改和设置

本文深入解析线段树数据结构,阐述其在处理区间查询和更新操作中的应用。通过一道具体题目,详细展示了线段树的构建、修改、设置及查询过程,包括如何处理延迟标记,提供了一段完整的AC代码作为示例。

CodeVS4927 线段树5


题意:

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

解题思路:

  • 线段树的的修改和设置
  • 设置两个值 set 和 add 分别表示设置和增加的延迟标记。用标记 f 这个区间上次的操作(1 表示上一次对这个区间的操作为设置,0 表示上次对这个区间操作为增加)。
  • debug太难了。 QwQ

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define rep(i,l,p) for(int i=l;i<=p;i++)
typedef long long ll;
const int N = 200005;
int n,m,a[N];
struct ST
{
    int l,r;
    bool f;
    ll add,sum,set,minval,maxval;
}t[4*N];
char op[5];
void build(int p,int l,int r){
    t[p].l = l,t[p].r = r;
    if(l==r){
        t[p].sum = a[l];
        t[p].minval = t[p].maxval = a[l];
        t[p].f = t[p].set = t[p].add = 0;
        return;
    }
    int mid = (l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p].sum = t[p*2].sum + t[p*2+1].sum;
    t[p].minval = min(t[p*2].minval,t[p*2+1].minval);
    t[p].maxval = max(t[p*2].maxval,t[p*2+1].maxval);
    t[p].f = t[p].set = 0;
    return ;
}
void spread(int p){
    if(t[p].l == t[p].r) return;
    if(t[p].f == 1){
        t[p*2].sum = t[p].set * (t[2*p].r - t[2*p].l +1);
        t[p*2+1].sum = t[p].set * (t[p*2+1].r - t[2*p+1].l +1);
        t[p*2].minval = t[p*2].maxval = t[p*2+1].minval = t[p*2+1].maxval = t[p].set;
        t[p*2].add = t[p*2+1].add = 0;
        t[p*2].f = t[p*2+1].f = 1; t[p].f = 0;
        t[p*2].set = t[p*2+1].set = t[p].set; t[p].set = 0;
        t[p].add = 0; // !!
    }
    if(t[p].add){
        if(t[2*p].set) t[p*2].set += t[p].add;
        else t[p*2].add += t[p].add;
        if(t[p*2+1].set) t[p*2+1].set += t[p].add;
        else t[p*2+1].add += t[p].add;
        t[p*2].sum += t[p].add * (t[p*2].r - t[p*2].l +1);
        t[p*2+1].sum += t[p].add * (t[p*2+1].r - t[p*2+1].l +1);
        t[p*2].maxval += t[p].add; t[p*2].minval += t[p].add;
        t[p*2+1].minval += t[p].add; t[p*2+1].maxval += t[p].add;
        t[p].add = 0; 
    }

}
void change(int p,int l,int r,int d){
    spread(p);
    if(l <= t[p].l && t[p].r <= r){
        if(t[p].set) t[p].set += d;
        else t[p].add += d;
        t[p].sum += (long long )d*(t[p].r - t[p].l+1);
        t[p].maxval += d; t[p].minval += d;
        return;
    }
    int mid = (t[p].r + t[p].l)/2;
    if(mid >= l) change(p*2,l,r,d);
    if(r > mid) change(p*2+1,l,r,d);
    t[p].minval = min(t[p*2].minval,t[p*2+1].minval);
    t[p].maxval = max(t[p*2].maxval,t[p*2+1].maxval);
    t[p].sum = t[p*2].sum+t[p*2+1].sum;
    return ;
}
void setval(int p,int l,int r,int d){
    if(l <= t[p].l && t[p].r <= r){
        t[p].sum = (long long )d*(t[p].r - t[p].l +1);
        t[p].set = d;
        t[p].minval = t[p].maxval = d;
        t[p].add = 0;
        t[p].f = 1;
        return;
    }
    spread(p);
    int mid = (t[p].l+t[p].r)/2;
    if(l <= mid) setval(2*p,l,r,d);
    if(r > mid) setval(p*2+1,l,r,d);
    t[p].sum = t[2*p].sum + t[2*p+1].sum;
    t[p].minval = min(t[p*2].minval,t[p*2+1].minval);
    t[p].maxval = max(t[p*2].maxval,t[p*2+1].maxval);
    return;
}
ll ask(int p,int l,int r){
    if(l <= t[p].l && t[p].r <= r){
        if(op[0] == 's') return t[p].sum;
        else if(op[1] == 'a') return t[p].maxval;
        else return t[p].minval;
    }
    spread(p);
    int mid = (t[p].l + t[p].r)/2;
    if(op[0] == 's'){
        ll res = 0;
        if(l <= mid) res += ask(2*p,l,r);
        if(r > mid) res += ask(2*p+1,l,r);
        return res;
    }else if(op[1] == 'a'){
        ll res = -1e18;
        if(l <= mid) res = max(res,ask(2*p,l,r)); 
         // cout << res << endl;
        if(r > mid) res = max(res,ask(2*p+1,l,r));
        // cout << res << endl << endl;
        return res;
    }else{
        ll res = 1e18;
        if(l<=mid) res = min(ask(2*p,l,r),res);
        if(r >mid) res = min(res,ask(2*p+1,l,r));
        return res;
    }
}
int main(int argc, char const *argv[])
{
    while(~scanf("%d%d",&n,&m)){
        rep(i,1,n) scanf("%d",&a[i]);
        build(1,1,n);
        int a,b,d;
        rep(i,1,m){
            scanf("%s%d%d",op,&a,&b);
            if(op[1] == 'e'){
                scanf("%d",&d);
                setval(1,a,b,d);
            }else if(op[1] == 'd'){
                scanf("%d",&d);
                change(1,a,b,d);
            }else{
                printf("%lld\n",ask(1,a,b));
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值