CodeVS5037线段树练习4加强版

来源:互联网 发布:叉叉助手网络连接失败 编辑:程序博客网 时间:2024/04/29 03:00

链接

  http://codevs.cn/problem/5037/

题解

  基本思想:分块记录每个块内各种数字的数量,然后统计,时空复杂度O(N*sqrt(N))。

  像这种题目线段树一般做不了,因为有K种不同的数字(你不可能对每个节点都开一个大小为K的数组,但你完全可以对每一个块开一个),类似的还有K种颜色..etc。

代码

//分块#include <cstdio>#include <algorithm>#include <cmath>#define maxn 200100#define maxsz 450int lp[maxn+maxsz], cnt[maxn/maxsz+10][maxn], N, M, K, num[maxn], tag[maxn/maxsz+10],size;inline int read(int x=0){char c=getchar();while(c<48 or c>58)c=getchar();while(c>=48 and c<=58)x=x*10+c-48,c=getchar();return x;}inline char getc(){char c=getchar();while(c<'a' or c>'z')c=getchar();return c;}inline void init(){int i;size=sqrt(N);for(i=0;i<N;i++){scanf("%d",num+i);cnt[lp[i]=i/size][num[i]%=K]++;}for(i=N;i<=N+size;i++)lp[i]=i/size;}inline void add1(int x, int d){cnt[lp[x]][num[x]]--;cnt[lp[x]][num[x]=(num[x]+d)%K]++;}inline void add(int l, int r, int v){int i;for(i=l;lp[i]==lp[l] and i<=r;i++)add1(i,v);if(lp[l]^lp[r])for(i=r;lp[i]==lp[r];i--)add1(i,v);for(i=lp[l]+1;i<lp[r];i++)tag[i]+=v;}inline int count(int l, int r){int i, ans=0, t;for(i=l,t=tag[lp[l]]%K;lp[i]==lp[l] and i<=r;i++)if((!num[i] and !t) or num[i]+t==K)ans++;if(lp[l]^lp[r])for(i=r,t=tag[lp[r]]%K;lp[i]==lp[r];i--)if((!num[i] and !t) or num[i]+t==K)ans++;for(i=lp[l]+1;i<lp[r];i++)ans+=cnt[i][(K-(tag[i]%=K))^K?K-tag[i]:0];return ans;}int main(){int l, r, v;char type;N=read(), M=read(), K=read();init();while(M--){type=getc(), l=read()-1, r=read()-1;if(type=='c')printf("%d\n",count(l,r));else v=read()%K, add(l,r,v);}return 0;}


0 0