lightOJ 1135 lazy 操作

本文介绍了一种使用线段树解决区间加一操作和查询区间内能被三整除的数的个数的问题。文章详细阐述了线段树的构造、更新、查询方法,并通过实例演示了如何优化代码避免常见错误,如数组大小不足、初始化错误等。此外,文章还提到了在代码实现中的一些技巧和注意事项,如使用中间变量和函数来简化代码。通过本教程,读者可以学会如何高效地使用线段树解决类似问题。

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

有n个数,刚开始都为0 http://www.cnblogs.com/wuyiqi/archive/2012/05/27/2520642.html
add i , j 给i,j区间内的数都加1
Q i j 询问i、j间能被三整除的数的个数 http://lightoj.com/volume_showproblem.php?problem=1135
线段树记录三个域
对三取余为0的数的个数
。。。。。1.。。。。。
。。。。。2.。。。。。
可以保存在一个数组里面
考虑到每次给一个区间加1的时候,区间内对3取余为1的数的个数变成了对三取余为2,2的变成了0,0的变成了1

所以每次更新到区间或者把信息(懒惰标记)往下传的时候只需要把相应的域做一下调整即可

做题过程:(在程序里面有写)

       我发觉数组真的是和我过不去额。又开小了。10^5我以为5个1就行了呢。。。

       然后就是我常犯的毛病:不看题(人家是从0-n-1),还有就是初始化(lazy没有初始化)。

       这些都是后来的事情了。刚开始我图方便,将build直接写成memset了。然后一看结果输出的都是0,我就煞那间醒悟了,但是把lazy给漏掉了。。。

       还有一点是中间需要一个ans数组作为中间变量,不然的话,原来的值就被覆盖了。

       最后优化的一点是将那个1转成2等等的东西写成一个函数。

//started at 22:18
//submit at 22:47 RE
//change the size of shuzu ,submit at 22:49 WA
//change the start point and end point , submit at 22:51 WA
//change lazy[](initualize) ,submit ant 22 : 55, AC
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define lson l, m , rt << 1
#define rson m + 1, r, rt << 1 | 1
#define ls rt << 1
#define rs rt << 1 | 1
#define maxn 111111//RE了一次
#define havem int m = (l + r) >> 1
int hehe[3][maxn << 2],ans[3],lazy[maxn << 2];
void push_up(int rt){
    for(int i = 0; i < 3; i ++){
        hehe[i][rt] = hehe[i][ls] + hehe[i][rs];
    }
}
void build(int l,int r,int rt){
    lazy[rt] = 0;//这里wa了一次
    if(l == r){
        hehe[0][rt] = 1;
        hehe[1][rt] = hehe[2][rt] = 0;
        return ;
    }havem;
    build(lson); build(rson);
    push_up(rt);
}
int t,n,Q,op,a,b;
void make(int add, int rt){//这里优化了一下
    for(int i = 0; i < 3; i ++){
        ans[(i + add) % 3] = hehe[i][rt];
    }
    for(int i = 0; i < 3; i ++){
        hehe[i][rt] = ans[i];
    }
}
void push_dn(int rt){
    if(lazy[rt]){
        int tmp = lazy[rt];
        lazy[ls] += tmp;
        lazy[rs] += tmp;
        make(tmp,ls);
        make(tmp,rs);
        lazy[rt] = 0;
    }
}
void update(int L, int R,int l,int r, int rt){
    if(L <= l && r <= R){
        lazy[rt] += 1;
    //question : how do you increase the number
        make(1,rt);
        return;
    }havem;
    push_dn(rt);
    if(L <= m) update(L,R,lson);
    if(R > m) update(L,R,rson);
    push_up(rt);
}
int query(int L,int R,int l,int r,int rt){
    if(L <= l && r <= R)    return hehe[0][rt];
    int ret = 0;
    havem;  push_dn(rt);
    if(L <= m) ret = query(L,R,lson);
    if(R > m) ret += query(L,R,rson);
    return ret;
}
int main(){
    scanf("%d",&t);
    for(int ca = 1; ca <= t; ca ++){
        scanf("%d%d",&n,&Q);
        build(0,n - 1,1);//从0-n-1,wa了一次
        memset(ans,0,sizeof(ans));
        printf("Case %d:\n",ca);
        for(int i = 1; i <= Q; i ++){
            scanf("%d",&op);
            scanf("%d%d",&a,&b);
            if(op == 0){
                update(a,b,0,n - 1,1);
            }else
                printf("%d\n",query(a,b,0,n - 1,1));
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值