感觉这才算入门题吧。。前面那些线段树练习,改几个字符就过了一定要搞成几道题。。
n<=2e5的数列,给常数K<=2e5,m<=2e5个操作,区间加,问一个区间里K的倍数。
这题空间???当成512MB吧。。n*sqrt(n)开得下
每个块记cnt(x,i)表示第x个块有多少数%K=i,以及整块+标记add(x),然后回答询问时默认一个块里的数都加上了add(x)即可,修改常规。
1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 #include<stdlib.h> 5 #include<math.h> 6 //#include<iostream> 7 using namespace std; 8 9 int n,m,q,K; 10 #define maxn 200011 11 #define maxm 461 12 int cnt[maxm][maxn],a[maxn],bel[maxn],tot,add[maxm]; 13 void modify(int x,int y,int v) 14 { 15 if (bel[x]==bel[y]) 16 for (int i=x;i<=y;i++) cnt[bel[i]][a[i]]--,a[i]+=v,a[i]%=K,cnt[bel[i]][a[i]]++; 17 else 18 { 19 for (int i=bel[x]+1;i<bel[y];i++) add[i]+=v,add[i]%=K; 20 for (int i=x;bel[i]==bel[x];i++) cnt[bel[i]][a[i]]--,a[i]+=v,a[i]%=K,cnt[bel[i]][a[i]]++; 21 for (int i=y;bel[i]==bel[y];i--) cnt[bel[i]][a[i]]--,a[i]+=v,a[i]%=K,cnt[bel[i]][a[i]]++; 22 } 23 } 24 int query(int x,int y) 25 { 26 int ans=0; 27 if (bel[x]==bel[y]) 28 for (int i=x;i<=y;i++) ans+=(a[i]+add[bel[i]]==0 || a[i]+add[bel[i]]==K); 29 else 30 { 31 for (int i=bel[x]+1;i<bel[y];i++) ans+=cnt[i][add[i]?K-add[i]:0]; 32 for (int i=x;bel[x]==bel[i];i++) ans+=(a[i]+add[bel[i]]==0 || a[i]+add[bel[i]]==K); 33 for (int i=y;bel[y]==bel[i];i--) ans+=(a[i]+add[bel[i]]==0 || a[i]+add[bel[i]]==K); 34 } 35 return ans; 36 } 37 38 bool isdigit(char c) {return c>='0' && c<='9';} 39 int qread() 40 { 41 char c;int s=0;while (!isdigit(c=getchar())); 42 do s=s*10+c-'0'; while (isdigit(c=getchar())); return s; 43 } 44 int main() 45 { 46 n=qread(),q=qread(),K=qread(); 47 m=(int)sqrt(n); 48 for (int i=1;i<=n;i++) bel[i]=(i-1)/m+1; 49 tot=bel[n]; 50 51 for (int i=1;i<=n;i++) 52 { 53 a[i]=qread()%K; 54 cnt[bel[i]][a[i]]++; 55 } 56 57 char c; 58 for (int i=1,x,y,z;i<=q;i++) 59 { 60 while (!((c=getchar())>='a' && c<='z')); 61 if (c=='a') 62 { 63 x=qread(),y=qread(),z=qread(); 64 modify(x,y,z); 65 } 66 else 67 { 68 x=qread(),y=qread(); 69 printf("%d ",query(x,y)); 70 } 71 while (c>='a' && c<='z') c=getchar(); 72 } 73 return 0; 74 }