Multiples of 3 线段树+spoj

Multiples of 3

Problem code: MULTQ3


There are N numbers a[0],a[1]..a[N - 1]. Initally all are 0. You have to perform two types of operations :

1) Increase the numbers between indices A and B (inclusive) by 1. This is represented by the command "0 A B"
2) Answer how many numbers between indices A and B (inclusive) are divisible by 3. This is represented by the command "1 A B".

Input :
The first line contains two integers, N and Q. Each of the next Q lines are either of the form "0 A B" or "1 A B" as mentioned above.

Output :
Output 1 line for each of the queries of the form "1 A B" containing the required answer for the corresponding query.

Sample Input :
4 7
1 0 3
0 1 2
0 1 3
1 0 0
0 0 3
1 3 3
1 0 3 

Sample Output :
4
1
0
2

Constraints :
1 <= N <= 100000
1 <= Q <= 100000
0 <= A <= B <= N - 1

解决方案:这题要维护四个信息,1)除3余0的sum[0][rt],2)除3余1的sum[1][rt],3)除3余2的sum[2][rt],加上一个lazy标志add[rt],在加1的过程,即为三个状态:sum[0][rt]、sum[1][rt]、sum[2][rt]之间的转换,是加1转换还是加2转换由add[rt]来决定。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#define MMAX 100003
using namespace std;
int sum[3][4*MMAX],add[4*MMAX];
int n,q;
int _sum;
void build(int rt,int L,int R)
{
    if(L==R)
    {
        sum[0][rt]=1;
    }
    else
    {
        int l=rt*2,r=rt*2+1;
        int M=(L+R)/2;
        build(l,L,M);
        build(r,M+1,R);
        sum[0][rt]=sum[0][l]+sum[0][r];
    }


}
void push_up(int rt)
{
    int l=rt*2,r=rt*2+1;
    sum[0][rt]=sum[0][l]+sum[0][r];
    sum[1][rt]=sum[1][l]+sum[1][r];
    sum[2][rt]=sum[2][l]+sum[2][r];

}
void push_down(int rt)
{
    int l=rt*2,r=rt*2+1;
    if(add[rt]!=0)
    {
        add[l]=(add[l]+add[rt])%3;
        add[r]=(add[r]+add[rt])%3;
        if(add[rt]==1)
        {
            int temp=sum[2][l];
            sum[2][l]=sum[1][l];
            sum[1][l]=sum[0][l];
            sum[0][l]=temp;

        }
        else if(add[rt]==2)
        {
            int temp=sum[0][l];
            sum[0][l]=sum[1][l];
            sum[1][l]=sum[2][l];
            sum[2][l]=temp;

        }
        if(add[rt]==1)
        {
            int temp=sum[2][r];
            sum[2][r]=sum[1][r];
            sum[1][r]=sum[0][r];
            sum[0][r]=temp;
        }
        else if(add[rt]==2)
        {
            int temp=sum[0][r];
            sum[0][r]=sum[1][r];
            sum[1][r]=sum[2][r];
            sum[2][r]=temp;

        }
        add[rt]=0;
    }



}
void update(int rt,int L,int R,int sl,int sr)
{
    if(sl<=L&&sr>=R)
    {
        int temp=sum[2][rt];
        sum[2][rt]=sum[1][rt];
        sum[1][rt]=sum[0][rt];
        sum[0][rt]=temp;
        add[rt]=(add[rt]+1)%3;
        return ;
    }

    push_down(rt);
    int m=(L+R)/2;
    if(sl<=m) update(rt*2,L,m,sl,sr);
    if(sr>m) update(rt*2+1,m+1,R,sl,sr);
    push_up(rt);
}
void query(int rt,int L,int R,int ql,int qr){

    if(ql<=L&&qr>=R){
        _sum+=sum[0][rt];
    }
    else{
        push_down(rt);
        int m=(L+R)/2;
        if(ql<=m)query(rt*2,L,m,ql,qr);
        if(qr>m) query(rt*2+1,m+1,R,ql,qr);
    }

}
int main()
{
    while(~scanf("%d%d",&n,&q)){
       build(1,1,n);
       int a,b,c;
       for(int i=1;i<=q;i++){
            scanf("%d%d%d",&a,&b,&c);
         if(a==1){
           _sum=0;
           query(1,1,n,b+1,c+1);
           printf("%d\n",_sum);
         }
         else {
            update(1,1,n,b+1,c+1);
         }
       }

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值