codevs5037 分块

题目分析

首先,这题虽然叫做线段树练习4,但是好像不能用线段树做?可能也是我太弱了,树王大佬应该就能用线段树做吧。
那么这题最好用的数据结构是分块!
好吧我不说了,解析都在代码里。

代码

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
#define ll long long
int read(){
    int q=0;char ch=' ';
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')q=q*10+ch-'0',ch=getchar();
    return q;
}
const int maxn=200505;
int mod,n,m,sqn;
int pos[maxn],a[maxn],laz[maxn],sum[500][maxn];
//pos:记录每个位置在哪一块,a:每个位置的数%mod后的数,laz:懒惰标记,表示
//这个块i里的数都要加上laz[i],sum表示每个块里%mod余1,2,3...的数的个数
void add(int x,int y,int z){
    int i,j,lim;
    lim=min(pos[x]*sqn,y);
    for(i=x;i<=lim;i++){
        sum[pos[i]][a[i]]--;
        a[i]=(a[i]+z)%mod;
        sum[pos[i]][a[i]]++;
    }
    if(pos[x]!=pos[y]){
        lim=(pos[y]-1)*sqn+1;
        for(i=lim;i<=y;i++){
            sum[pos[i]][a[i]]--;
            a[i]=(a[i]+z)%mod;
            sum[pos[i]][a[i]]++;
        }
    }
    for(i=pos[x]+1;i<pos[y];i++){laz[i]+=z;laz[i]%=mod;}
}
int find(int x,int y){
    int i,j,re=0,lim;
    lim=min(pos[x]*sqn,y);
    for(i=x;i<=lim;i++)if((a[i]+laz[pos[i]])%mod==0)re++;
    if(pos[x]!=pos[y]){
        lim=(pos[y]-1)*sqn+1;
        for(i=lim;i<=y;i++)
            if((a[i]+laz[pos[i]])%mod==0)re++;
    }
    for(i=pos[x]+1;i<pos[y];i++)re+=sum[i][(mod-laz[i])%mod];
    //注意这里,如果laz[i]=0的话,应该查的是sum[i][0]而非sum[i][mod]
    return re;
}
int main()
{
    int i,x,y,z;char ch[10];
    n=read();m=read();mod=read();sqn=sqrt(n);
    for(i=1;i<=n;i++){
        pos[i]=(i-1)/sqn+1;
        a[i]=read();a[i]%=mod;sum[pos[i]][a[i]]++;
    }
    for(i=1;i<=m;i++){
        scanf("%s",ch);
        if(ch[0]=='a'){x=read();y=read();z=read();add(x,y,z);}
        else {x=read();y=read();printf("%d\n",find(x,y));}
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值