这个题……表示不知道怎么用线段树做……空间不够用啊……只会分块了qwq
分块的思想就是把整个区间分成若干个区间,操作中,若一个小区间完全被覆盖,则把状态加入一个存储的数组,否则直接下放到每个点
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; const int mo=500; char s[10]; int n,m,k,x,y,z,chu[200020],seg[404],k1[404][200020]; inline void re(int &a)//读入优化 { a=0; bool flag=0; char b=getchar(); while(b<'0'||b>'9') { if(b=='-') flag=1; b=getchar(); } while(b>='0'&&b<='9') a=a*10+b-'0',b=getchar(); } void add(int l,int r,int j) { int fir=(l-1)/mo+1,las=(r-1)/mo;//fir是左端点所在的区间,las是右端点所在区间的左边的区间 if(las<fir)//说明这两个点在同一个或者相邻两个区间里 for(int i=l;i<=r;i++) { k1[fir][chu[i]%k]--; chu[i]+=j; k1[fir][chu[i]%k]++; } else//否则说明至少跨过三个区间 { for(int i=l;i<=fir*mo;i++)//模拟过程,开头这一段不能完全覆盖所在区间,则一个个点修改 { k1[fir][chu[i]%k]--; chu[i]+=j; k1[fir][chu[i]%k]++; } for(int i=fir+1;i<=las;i++) seg[i]+=j; for(int i=las*mo+1;i<=r;i++)//最后一段也是 { k1[las+1][chu[i]%k]--; chu[i]+=j; k1[las+1][chu[i]%k]++; } } } void ask(int l,int r) { int fir=(l-1)/mo+1,ans=0,las=(r-1)/mo; if(las<fir)//思想基本同上 { for(int i=l;i<=r;i++) { if((chu[i]+seg[fir])%k==0) ans++; } } else { for(int i=l;i<=fir*mo;i++) if((chu[i]+seg[fir])%k==0) ans++; for(int i=fir+1;i<=las;i++) ans+=k1[i][(k-seg[i]%k)%k]; for(int i=las*mo+1;i<=r;i++) if((chu[i]+seg[las+1])%k==0) ans++; } printf("%d\n",ans); } int main() { re(n),re(m),re(k); for(int i=1;i<=n;i++) re(chu[i]),k1[(i-1)/mo+1][chu[i]%k]++;//分块初始化,我设定每500个元素分个块 for(int i=1;i<=m;i++) { scanf("%s",s); if(s[0]=='a') re(x),re(y),re(z),add(x,y,z);//加值 else re(x),re(y),ask(x,y);//查询 } }