[codevs] 线段树练习4

题目描述:
给你N个数,有两种操作
1:给区间[a,b]内的所有数都增加X
2:询问区间[a,b]能被7整除的个数

输入描述:
第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数。如果第一个数是add,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是count,表示统计区间[a,b]能被7整除的个数

输出描述:
对于每个询问输出一行一个答案

样例输入:
3
2 3 4
6
count 1 3
count 1 2
add 1 3 2
count 1 3
add 1 3 3
count 1 3

样例输出:
0
0
0
1

数据范围:1<=N,Q<=100000

题解:
很简单的线段树练习,给线段树的每一个节点开一个小数组g[i]表示这个节点表示的区间内的所有数对7取模的结果为i的数有多少个。然后就跟普通的线段树一样做咯。

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<queue>
#define LiangJiaJun main
using namespace std;
int n,q;
int a[100004];
struct data{
     int g[10];
     int l,r,tag;
}tr[400004];
void build(int k,int l,int r){
     tr[k].l=l;tr[k].r=r;
     if(l==r){
         tr[k].g[a[l]]=1;return;
     }
     int mid=(l+r)>>1;
     build(k<<1,l,mid);
     build(k<<1|1,mid+1,r);
     for(int i=0;i<7;i++)
        tr[k].g[i]=tr[k<<1].g[i]+tr[k<<1|1].g[i];
}
void update(int k,int pd){
     int s[10];
     for(int i=0;i<7;i++)s[(i+pd)%7]=tr[k].g[i];
     for(int i=0;i<7;i++)tr[k].g[i]=s[i];
}
void push(int k){
     int pd=tr[k].tag%7;
     update(k<<1,pd);update(k<<1|1,pd);
     tr[k<<1].tag+=pd;
     tr[k<<1|1].tag+=pd;
     tr[k].tag=0;
}
void add(int k,int a,int b,int w){
     int l=tr[k].l,r=tr[k].r;
     if(l==a&&r==b){
        tr[k].tag+=w;
        update(k,w);
        return;
     }
     if(tr[k].tag)push(k);
     int mid=(l+r)>>1;
     if(b<=mid)add(k<<1,a,b,w);
     else if(a>mid)add(k<<1|1,a,b,w);
     else {
        add(k<<1,a,mid,w);add(k<<1|1,mid+1,b,w);
     }
     for(int i=0;i<7;i++)
        tr[k].g[i]=tr[k<<1].g[i]+tr[k<<1|1].g[i];
}
int query(int k,int a,int b){
    int l=tr[k].l,r=tr[k].r;
    if(l==a&&r==b)return tr[k].g[0];
    if(tr[k].tag)push(k);
    int mid=(l+r)>>1;
    if(b<=mid)return query(k<<1,a,b);
    else if(a>mid)return query(k<<1|1,a,b);
    else{
        return (query(k<<1,a,mid)+query(k<<1|1,mid+1,b));
    }
}
int LiangJiaJun(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),a[i]%=7;
    build(1,1,n);
    scanf("%d",&q);
    while(q--){
        char ch[14];
        int x,y,z;
        scanf("%s",ch);
        if(ch[0]=='a'){
            scanf("%d%d%d",&x,&y,&z);
            z%=7;if(z==0)continue;
            add(1,x,y,z);
        }
        else{
            scanf("%d%d",&x,&y);
            printf("%d\n",query(1,x,y));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值