【学习】分块
题目及思路来自 hzwer.com
题目来自LOJ数列分块入门by hzw
持续咕咕咕中~
数列分块入门1
区间加,单点查询
code
1 void add(int a,int b,int c){ 2 for(int i=a;i<=min(b,blo[a]*block);i++){ 3 v[i]+=c; 4 } 5 if(blo[a]!=blo[b]){ 6 for(int i=(blo[b]-1)*block+1;i<=b;i++){ 7 v[i]+=c; 8 } 9 } 10 for(int i=blo[a]+1;i<=blo[b]-1;i++){ 11 tg[i]+=c; 12 } 13 }
1 if(f==1)printf("%d\n",v[b]+tg[blo[b]]);
数列分块入门2
区间加,查询区间内小于x的元素个数
块内set维护
code
1 int query(int a,int b,int c) 2 { 3 int ans=0; 4 for(int i=a;i<=min(bl[a]*blo,b);i++) 5 if(v[i]+atag[bl[a]]<c)ans++; 6 if(bl[a]!=bl[b]) 7 for(int i=(bl[b]-1)*blo+1;i<=b;i++) 8 if(v[i]+atag[bl[b]]<c)ans++; 9 for(int i=bl[a]+1;i<=bl[b]-1;i++) 10 { 11 int x=c-atag[i]; 12 ans+=lower_bound(ve[i].begin(),ve[i].end(),x)-ve[i].begin(); 13 } 14 return ans; 15 }
数列分块入门4
区间加,区间求和
先预处理区间和后再同上
code
1 void add(int l,int r,int c){ 2 for(int i=l;i<=min(r,bl[l]*block);i++){ 3 sum[bl[l]]+=c;v[i]+=c; 4 } 5 if(bl[l]!=bl[r]){ 6 for(int i=(bl[r]-1)*block+1;i<=r;i++){ 7 sum[bl[r]]+=c;v[i]+=c; 8 } 9 } 10 for(int i=bl[l]+1;i<=bl[r]-1;i++){ 11 tg[i]+=c; 12 } 13 }
1 ll query(int l,int r){ 2 int ans=0; 3 for(int i=l;i<=min(r,bl[l]*block);i++){ 4 ans+=v[i]+tg[bl[l]]; 5 } 6 if(bl[l]!=bl[r]){ 7 for(int i=(bl[r]-1)*block+1;i<=r;i++){ 8 ans+=v[i]+tg[bl[r]]; 9 } 10 } 11 for(int i=bl[l]+1;i<=bl[r]-1;i++){ 12 ans+=sum[i]+block*tg[i]; 13 } 14 return ans; 15 } 16 17 18 19 if(op==1)printf("%lld\n",query(l,r)%(c+1));
数列分块入门7
区间乘,区间加
维护multi-tag和add-tag同时乘法的优先级高于加法
code
1 void solve(int f,int l,int r,int c){ 2 reset(bl[l]); 3 for(int i=l;i<=min(bl[l]*blo,r);i++){ 4 if(f==0)v[i]+=c; 5 else v[i]*=c; 6 v[i]%=mod; 7 } 8 if(bl[l]!=bl[r]){ 9 reset(bl[r]); 10 for(int i=(bl[r]-1)*blo+1;i<=r;i++){ 11 if(f==0)v[i]+=c; 12 else v[i]*=c; 13 v[i]%=mod; 14 } 15 } 16 for(int i=bl[l]+1;i<=bl[r]-1;i++){ 17 if(f==0)atg[i]=(atg[i]+c)%mod; 18 else { 19 atg[i]=(atg[i]*c)%mod; 20 mtg[i]=(mtg[i]*c)%mod; 21 } 22 } 23 }
1 void reset(int x){ 2 for(int i=(x-1)*blo+1;i<=min(n,x*blo);i++){ 3 v[i]=(v[i]*mtg[x]+atg[x])%mod; 4 } 5 atg[x]=0;mtg[x]=1; 6 }