P1253 扶苏的问题(洛谷)(线段树)

文章介绍了一种使用二分树结构处理覆盖值和累加值的算法,其中tag值存储覆盖值和累加值,通过push_down函数传播覆盖信息,updata函数用于更新区间值,query函数查询最大值。代码中特别注意了覆盖值可能为0的情况,使用了一个极小值(-1e18)作为判断条件。
摘要由CSDN通过智能技术生成

     tag值存两个,一个覆盖值,一个累加值,再开一个变量存是否有覆盖值。因为覆盖值可能为零,也可以置为一个极小的值作为覆盖值是否存在的判断条件(如-1e18),除了注释的部分要注意一下以外,其余纯模板。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
#define int long long
typedef pair<int, int> PII;
int n, m, k;
int T;
int a[N];
int tree[N * 4];
struct node
{
    int x, y, z;          //分别指的是覆盖值,累加值和是否有覆盖值。只需要维护覆盖值,不需要维护累加值
} tag[N * 4];
void push_up(int rt)
{
    tree[rt] = max(tree[rt << 1], tree[rt << 1 | 1]);
}

void build(int rt, int l, int r)
{
    if (l == r)
    {
        tree[rt] = a[l];
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    push_up(rt);
}

void push_down(int rt)
{
    if(tag[rt].z)       //如果有覆盖值
    {
        tag[rt<<1].x = tag[rt].x, tag[rt<<1|1].x = tag[rt].x;
        tag[rt<<1].y = tag[rt].y, tag[rt<<1|1].y = tag[rt].y; //特别注意这里的累加值要直接赋值过去,而不是+=
        tag[rt<<1].z = tag[rt<<1|1].z = 1;                   //因为若存在覆盖值,之前存在的累加值就已经没有意义
        tree[rt<<1] = tag[rt].x + tag[rt].y;
        tree[rt<<1|1] = tag[rt].x + tag[rt].y;
    }
    else
    {
        tag[rt<<1].y += tag[rt].y;
        tag[rt<<1|1].y += tag[rt].y;
        tree[rt<<1] += tag[rt].y;
        tree[rt<<1|1] += tag[rt].y;
    }
    tag[rt].x = tag[rt].y = tag[rt].z = 0;
}

void updata(int rt, int l, int r, int start, int end, int data, int f)
{
    if(f==1)
    {
        if(start <= l && end >= r)
        {
            tag[rt].x = data;
            tag[rt].y = 0;        //累加值置为0,都被覆盖了,已经没有意义
            tree[rt] = data;
            tag[rt].z = 1;        //存在覆盖值(覆盖值可以是零,所以不能用tag[i].x==0作为判断条件)
            return;
        }
    }
    else
    {
        if(start <= l && end >= r)
        {
            tree[rt] += data;
            tag[rt].y += data;
            return;
        }
    }
    push_down(rt);
    int mid = l + r >> 1;
    if(start <= mid) updata(rt<<1, l, mid, start, end, data, f);
    if(end >= mid + 1) updata(rt<<1|1, mid+1, r, start, end, data, f);
    push_up(rt); 
}

int query(int rt, int l, int r, int start, int end)
{
    if(start <= l && end >= r)
        return tree[rt];
    push_down(rt);
    int res = -1e18;          //因为会爆int,一定要非常小,没注意到,写的0x3f3f3f3f卡好久
    int mid = l + r >> 1;
    if(start <= mid) res = max(res, query(rt<<1, l, mid, start, end));
    if(end >= mid+1) res = max(res, query(rt<<1|1, mid+1, r, start, end));
    return res;
}

signed main()
{
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    build(1, 1, n);
    while (m--)
    {
        int a, b, c, d;
        cin >> k;
        if (k == 1)
        {
            cin >> a >> b >> c;
            updata(1, 1, n, a, b, c, 1);
        }
        else if (k == 2)
        {
            cin >> a >> b >> c;
            updata(1, 1, n, a, b, c, 2);
        }
        else
        {
            cin >> a >> b;
            int t = query(1, 1, n, a, b);
            cout << t << "\n";
        }
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值