一、数列分块入门1[区间修改,单点查询]
题目链接:https://loj.ac/problem/6277
【分析】把n分成n/k+(n%k ? 1 : 0)个块,其中k=sqrt(n),也就是每个块的大小为k,当区间[l,r]内包含某个块的全部时,给该块做个标记即可,其余部分暴力更新,时间复杂度为O(k);
【知识点】区间修改,单点查询
代码实现1:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e4+10;
int n,a[N],k,opt,l,r,c,cnt[N];
int main(){
scanf("%d",&n);
for(int i = 0; i < n; i ++) scanf("%d",&a[i]);
int k = int(sqrt(n));
for(int i = 1; i <= n; i ++){
scanf("%d%d%d%d",&opt,&l,&r,&c);
if(opt){
r --;
printf("%d\n",a[r]+cnt[r/k]);
}
else{
l --; r --;
while(l%k && l <= r){
a[l] += c; l ++;
}
while(l+k<=r){
cnt[l/k] += c;
l += k;
}
while(l<=r) a[l]+=c,l++;
}
}
return 0;
}
代码实现2:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e4+10;
int n,a[N],k,opt,l,r,c,cnt[N],bl[N];
void add(int l, int r, int c){
for(int i = l; i <= min(bl[l]*k,r); i ++) a[i] += c;
if(bl[l] != bl[r]){
for(int i = (bl[r]-1)*k+1; i <= r; i ++) a[i] += c;
}
for(int i = bl[l]+1; i <= bl[r]-1; i ++) cnt[i] += c;
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i ++) scanf("%d",&a[i]);
k = int(sqrt(n));
for(int i = 1; i <= n; i ++) bl[i] = (i-1)/k+1;
for(int i = 1; i <= n; i ++){
scanf("%d%d%d%d",&opt,&l,&r,&c);
if(opt) printf("%d\n",a[r] + cnt[bl[r]]);
else add(l,r,c);
}
return 0;
}
二、数列分块入门2
题目链接:https://loj.ac/problem/6278
【知识点】区间修改,查询区间内小于x的元素有多少个。
【代码如下】
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4+10;
int a[N],n,atag[N],k,bl[N];
vector<int>vct[N];
void reset(int x){
vct[x].clear();
for(int i = (x-1)*k+1; i <= min(x*k,n); i ++) vct[x].push_back(a[i]);
sort(vct[x].begin(),vct[x].end());
}
void add(int l, int r, int c){
for(int i = l; i <= min(r,bl[l]*k); i ++) a[i] += c;
reset(bl[l]);
if(bl[l] != bl[r]){
for(int i = (bl[r]-1)*k+1; i <= r; i ++) a[i] += c;
reset(bl[r]);
}
for(int i = (bl[l]+1); i <= bl[r]-1; i ++) atag[i] += c;
}
int query(int l, int r, int x){
int ans = 0;
for(int i = l; i <= min(r,bl[l]*k); i ++) if(a[i] + atag[bl[l]] < x) ans ++;
if(bl[l] != bl[r]){
for(int i = (bl[r]-1)*k + 1; i <= r; i ++) if(a[i] + atag[bl[r]] < x) ans ++;
}
for(int i = bl[l]+1; i <= bl[r]-1; i ++){
int t = x - atag[i];
int indx = lower_bound(vct[i].begin(),vct[i].end(),t) - vct[i].begin();
ans += indx;
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i ++) scanf("%d",&a[i]);
k = sqrt(n);
for(int i = 1; i <= n; i ++) bl[i] = (i-1)/k+1,vct[bl[i]].push_back(a[i]);
for(int i = 1; i <= bl[n]; i ++) sort(vct[i].begin(),vct[i].end());
for(int i = 1; i <= n; i ++){
int l,r,c,opt;
scanf("%d%d%d%d",&opt,&l,&r,&c);
if(opt) printf("%d\n",query(l,r,c*c));
else add(l,r,c);
}
return 0;
}