codevs5037 线段树练习4加强版(暴力分块)

时间:2023-12-18 10:57:38

  求大爷教线段树怎么写啊QAQ

  只会写分块...一开始脑抽写成了O(NKlogN)还被CZL大爷嘲讽了一发T T

  f[i][j]表示在第i块中,模k为j的数有几个,然后每次修改的时候只需要打个标记,查询的时候直接加上标记查就行了

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=;
int n,m,k,blo,x,y,z;
int a[maxn],bl[maxn],blcnt[][maxn],bl2[maxn],bltag[maxn],bltag2[maxn];
char s[];
inline void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
#define update(x) x>=k&&(x-=k)
inline void change(int x,const int &delta)
{
int now=a[x];
blcnt[bl[x]][now]--;
now+=delta;update(now);
blcnt[bl[x]][now]++;
a[x]+=delta;update(a[x]);
}
inline void add(int l,int r,const int &delta)
{
for(int i=l;i<=min(r,bl[l]*blo);i++)change(i,delta);
if(bl[l]!=bl[r])for(int i=(bl[r]-)*blo+;i<=r;i++)change(i,delta);
for(int i=bl[l]+;i<bl[r];i++)
{
bltag[i]+=delta;update(bltag[i]);
bltag2[i]-=delta;bltag2[i]<&&(bltag2[i]+=k);
}
}
inline int min(int a,int b){return a<b?a:b;}
int query(int l,int r)
{
int ans=,tmp,mn=min(bl[l]*blo,r);
for(int i=l;i<=mn;i++)
ans+=((tmp=a[i]+bltag[bl[i]])==k||!tmp);
if(bl[l]!=bl[r])for(int i=(bl[r]-)*blo+;i<=r;i++)
ans+=((tmp=a[i]+bltag[bl[i]])==k||!tmp);
for(int i=bl[l]+;i<bl[r];i++)ans+=blcnt[i][bltag2[i]];
return ans;
}
int main()
{
read(n);read(m);read(k);blo=sqrt(n);
for(int i=;i<=n;i++)bl[i]=(i-)/blo+;
for(int i=;i<=n;i++)read(x),a[i]=x%k;
for(int i=;i<=n;i++)blcnt[bl[i]][a[i]]++;
for(int i=;i<=m;i++)
{
scanf("%s",s);read(x);read(y);
if(s[]=='a')
{
read(z);z%=k;
z<&&(z+=k);
add(x,y,z);
}
else printf("%d\n",query(x,y));
}
}