hiho一下 第二十二周 (线段树上存在冲突的区间修改操作)

这是一个关于在模拟都市游戏中买卖房产的问题。玩家需要处理房屋价格的变动并计算总价值。涉及两种事件:房屋自发的价格变动及政府调控。通过段树和懒惰标记优化算法解决大规模数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目1 : 更为复杂的买卖房屋姿势

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

小Hi和小Ho都是游戏迷,“模拟都市”是他们非常喜欢的一个游戏,在这个游戏里面他们可以化身上帝模式,买卖房产。

在这个游戏里,会不断的发生如下两种事件:一种是房屋自发的涨价或者降价,而另一种是政府有关部门针对房价的硬性调控。房价的变化自然影响到小Hi和小Ho的决策,所以他们希望能够知道任意时刻某个街道中所有房屋的房价总和是多少——但是很不幸的,游戏本身并不提供这样的计算。不过这难不倒小Hi和小Ho,他们将这个问题抽象了一下,成为了这样的问题:

小Hi和小Ho所关注的街道的长度为N米,从一端开始每隔1米就有一栋房屋,依次编号为0..N,在游戏的最开始,每栋房屋都有一个初始价格,其中编号为i的房屋的初始价格为p_i,之后共计发生了M次事件,所有的事件都是对于编号连续的一些房屋发生的,其中第i次事件如果是房屋自发的涨价或者降价,则被描述为三元组(L_i, R_i, D_i),表示编号在[L_i, R_i]范围内的房屋的价格的增量(即正数为涨价,负数为降价)为D_i;如果是政府有关部门针对房价的硬性调控,则被描述为三元组(L_i, R_i, V_i),表示编号在[L_i, R_i]范围内的房屋的价格全部变为V_i。而小Hi和小Ho希望知道的是——每次事件发生之后,这个街道中所有房屋的房价总和是多少。

提示:这是练习向的一周~

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第1行为两个整数N、M,分别表示街道的长度和总共发生的事件数。

每组测试数据的第2行为N+1个整数,其中第i个整数位p_i,表示编号为i的房屋的初始价格。

每组测试数据的第3-M+2行,按照发生的时间顺序,每行描述一个事件,如果该行描述的事件为,“房屋自发的涨价或者降价”,则该行为4个整数0, L_i, R_i, D_i,意义如前文所述;如果该行描述的事件为“政府有关部门针对房价的硬性调控”,则该行为4个整数1, L_i, R_i, V_i,意义如前文所述。

对于100%的数据,满足N<=10^5,1<=p_i, |D_i|, V_i<=10^4,0<=l_i<r_i<=n。<>

对于100%的数据,满足在任意时刻,任何房屋的价格都处于[1, 10^4]内。

输出

对于每组测试数据,输出M行,其中第i行为一个整数Ans_i,表示第i次事件发生之后,这个街道中所有房屋的房价总和。


样例输入
10 6
3195 2202 4613 3744 2892 4858 619 5079 9478 7366 8942 
0 1 6 886
1 0 2 9710
1 0 10 7980
0 4 9 -7594
0 2 8 1581
0 4 4 -1010
样例输出
58304
75652
87780
42216
53283

52273


说明:题目中有两种修改操作——并且都是区间修改,也就是说如果使用懒惰标记来维护修改的话,关键在于处理好这两种操作之间的冲突。

代码:

#include <iostream>
#include <cstdio>
using namespace std;

const int MAXN = 100005;

int N, M;
int segTree[MAXN*3];
int lazySet[MAXN*3];
int lazyAdd[MAXN*3];

void pushUp(int node){
    segTree[node] = segTree[2*node] + segTree[2*node+1];
}

void pushDown(int node, int begin, int end){
    int m = (begin+end)/2;
    if(lazySet[node]){
        lazyAdd[2*node] = lazyAdd[2*node+1] = 0; //最关键的在此
        lazySet[2*node] = lazySet[2*node+1] = lazySet[node];

        segTree[2*node] = (m-begin+1)*lazySet[node];
        segTree[2*node+1] = (end-m)*lazySet[node];
        lazySet[node] = 0;
    }
    if(lazyAdd[node]){
        lazyAdd[2*node] += lazyAdd[node];
        lazyAdd[2*node+1] += lazyAdd[node];
        segTree[2*node] += (m-begin+1)*lazyAdd[node];
        segTree[2*node+1] += (end-m)*lazyAdd[node];
        lazyAdd[node] = 0;
    }
}

void build(int node, int begin, int end){
    lazySet[node] = lazyAdd[node] = 0;
    if(begin == end) scanf("%d", &segTree[node]);
    else{
        int m = (begin+end)/2;
        build(2*node, begin, m);
        build(2*node+1, m+1, end);
        pushUp(node);
    }
}

void updateAdd(int node, int begin, int end, int a, int b, int c){
    if(begin==a && end==b){
        lazyAdd[node] += c;
        segTree[node] += (b-a+1)*c;
    }else{
        pushDown(node, begin, end);
        int m = (begin+end)/2;
        if(b<=m) updateAdd(2*node, begin, m, a, b, c);
        else if(m<a) updateAdd(2*node+1, m+1, end, a, b, c);
        else{
            updateAdd(2*node, begin, m, a, m, c);
            updateAdd(2*node+1, m+1, end, m+1, b, c);
        }
        pushUp(node);
    }
}

void updateSet(int node, int begin, int end, int a, int b, int c){
    if(begin==a && end==b){
        lazySet[node] = c;
        lazyAdd[node] = 0;
        segTree[node] = (b-a+1)*c;
    }else{
        pushDown(node, begin, end);
        int m = (begin+end)/2;
        if(b<=m) updateSet(2*node, begin, m, a, b, c);
        else if(a>m) updateSet(2*node+1, m+1, end, a, b, c);
        else{
            updateSet(2*node, begin, m, a, m, c);
            updateSet(2*node+1, m+1, end, m+1, b, c);
        }
        pushUp(node);
    }
}

int main(){
    int type, a, b, c;
    scanf("%d %d", &N, &M);
    build(1, 1, N+1);

    while(M--){
        scanf("%d %d %d %d", &type, &a, &b, &c);
        a++; b++;
        if(type == 0){
            //房屋自发的涨价或者降价
            updateAdd(1, 1, N+1, a, b, c);
        }else{
            //政府有关部门针对房价的硬性调控
            updateSet(1, 1, N+1, a, b, c);
        }
        printf("%d\n", segTree[1]);
    }
    return 0;
}


代码二(更简洁和高效一点,其实二者效率差不太多)

#include <iostream>
#include <cstdio>
using namespace std;

const int MAXN = 100005;

int N, M;
int segTree[MAXN*3];
int lazySet[MAXN*3];
int lazyAdd[MAXN*3];

void pushUp(int node){
    segTree[node] = segTree[node<<1] + segTree[node<<1|1];
}

void pushDown(int node, int begin, int end){
    int m = (begin+end)>>1;
    if(lazySet[node]){
        lazyAdd[node<<1] = lazyAdd[node<<1|1] = 0;
        lazySet[node<<1] = lazySet[node<<1|1] = lazySet[node];

        segTree[node<<1] = (m-begin+1)*lazySet[node];
        segTree[node<<1|1] = (end-m)*lazySet[node];
        lazySet[node] = 0;
    }
    if(lazyAdd[node]){
        lazyAdd[node<<1] += lazyAdd[node];
        lazyAdd[node<<1|1] += lazyAdd[node];
        segTree[node<<1] += (m-begin+1)*lazyAdd[node];
        segTree[node<<1|1] += (end-m)*lazyAdd[node];
        lazyAdd[node] = 0;
    }
}

void build(int node, int begin, int end){
    lazySet[node] = lazyAdd[node] = 0;
    if(begin == end){
        scanf("%d", &segTree[node]);
        return;
    }
    int m = (begin+end)>>1;
    build(node<<1, begin, m);
    build(node<<1|1, m+1, end);
    pushUp(node);
}

void updateAdd(int node, int begin, int end, int a, int b, int c){
    if(a<=begin && end<=b){
        lazyAdd[node] += c;
        segTree[node] += (end-begin+1)*c;
        return;
    }
    pushDown(node, begin, end);
    int m = (end+begin)>>1;
    if(a<=m) updateAdd(node<<1, begin, m, a, b, c);
    if(m<b) updateAdd(node<<1|1, m+1, end, a, b, c);
    pushUp(node);
}

void updateSet(int node, int begin, int end, int a, int b, int c){
    if(a<=begin && end<=b){
        lazySet[node] = c;
        lazyAdd[node] = 0;
        segTree[node] = (end-begin+1)*c;
        return;
    }
    pushDown(node, begin, end);
    int m = (begin+end)>>1;
    if(a<=m) updateSet(node<<1, begin, m, a, b, c);
    if(m<b) updateSet(node<<1|1, m+1, end, a, b, c);
    pushUp(node);
}

int main(){
    int type, a, b, c;
    scanf("%d %d", &N, &M);
    build(1, 1, N+1);

    while(M--){
        scanf("%d %d %d %d", &type, &a, &b, &c);
        a++; b++;
        if(type == 0){
            //房屋自发的涨价或者降价
            updateAdd(1, 1, N+1, a, b, c);
        }else{
            //政府有关部门针对房价的硬性调控
            updateSet(1, 1, N+1, a, b, c);
        }
        printf("%d\n", segTree[1]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值