light oj 1135 线段树 有助于加深对懒惰标记的理解

来源:互联网 发布:数据挖掘 数学基础 编辑:程序博客网 时间:2024/05/22 01:44

有n个数,刚开始都为0

add i , j 给i,j区间内的数都加1

Q i  j   询问i、j间能被三整除的数的个数

线段树记录三个域

对三取余为0的数的个数

。。。。。1.。。。。。

。。。。。2.。。。。。

可以保存在一个数组里面

考虑到每次给一个区间加1的时候,区间内对3取余为1的数的个数变成了对三取余为2,2的变成了0,0的变成了1

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

View Code
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn  =  100010;int cov[maxn<<2];int sum[maxn<<2][3];void pushup(int rt){    for(int i=0;i<3;i++){        sum[rt][i]=sum[rt<<1][i]+sum[rt<<1|1][i];    }}void build(int l,int r,int rt){    cov[rt]=0;    if(l==r){            sum[rt][0]=1;        sum[rt][1]=sum[rt][2]=0;        return ;    }    int m=(l+r)>>1;    build(lson);    build(rson);    pushup(rt);}void make(int rt){    int tmp=sum[rt][0];    sum[rt][0]=sum[rt][2];    sum[rt][2]=sum[rt][1];    sum[rt][1]=tmp;}void pushdown(int rt){    if(cov[rt]){        cov[rt<<1]+=cov[rt];        cov[rt<<1|1]+=cov[rt];        for(int i=0;i<cov[rt]%3;i++){            make(rt<<1);            make(rt<<1|1);        }        cov[rt]=0;    }}void update(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        cov[rt]++;        make(rt);        return ;    }    pushdown(rt);    int m=(l+r)>>1;    if(L<=m) update(L,R,lson);    if(R>m) update(L,R,rson);    pushup(rt);}int query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        return sum[rt][0];    }    pushdown(rt);    int m=(l+r)>>1;    int ret=0;    if(L<=m) ret+=query(L,R,lson);    if(R>m) ret+=query(L,R,rson);    return ret;}int main(){    int t,ca=1,i,j,k,a,b,n,q,op;    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&q);        printf("Case %d:\n",ca++);        build(1,n,1);        while(q--){            scanf("%d%d%d",&op,&a,&b);a++;b++;            if(op==0)  update(a,b,1,n,1);            else printf("%d\n",query(a,b,1,n,1));        }    }    return 0;}
原创粉丝点击