2025.7.8 分块
2025.7.8 分块
基本思想
通过对原数据的适当划分,并在划分后的每一个块上预处理部分信息,从而较一般的暴力算法取得更优的时间复杂度。
一般以 \(\sqrt{n}\) 为一个区间。
实现:以区间和为例
构造
void add(int p,int x){
id[p]=(p-1)/d+1;//d:划分范围
a[p]+=x;
qk[id[p]]+=x;//预处理
}
查询
int query(int l,int r){
int sum=0;
for(int i=l;i<=min(id[l]*d,r);i++){//不满一个区间
sum+=a[i];
}
if(id[l]!=id[r]){
for(int i=(id[r]-1)*d+1;i<=r;i++){//不满一个区间
sum+=a[i];
}
}
for(int i=id[l]+1;i<=id[r]-1;i++){//区间内
sum+=qk[i];
}
return sum;
}
例题P2464
题目描述
书架由 N 个书位组成,编号从 \(1\) 到 \(N\) 。每个书位放着一本书,每本书有一个特定的编码。
小 J 的工作有两类:
- 图书馆经常购置新书,而书架任意时刻都是满的,所以只得将某位置的书拿掉并换成新购的书。
- 小 J 需要回答顾客的查询,顾客会询问某一段连续的书位中某一特定编码的书有多少本。
第一行两个整数 \(N\) ,\(M\) ,表示一共 \(N\) 个书位,\(M\) 个操作。
接下来一行共 \(N\) 个整数数 \(A_1\),\(A_2\),…, \(A_N\) ,\(A_i\) 表示开始时位置 \(i\) 上的书的编码。
接下来 \(M\) 行,每行表示一次操作,每行开头一个字符。
若字符为 \(C\),表示图书馆购进新书,后接两个整数 \(A ,P\) \((1\leq{A}\leq{N})\) ,表示这本书被放在位置 \(A\) 上,以及这本书的编码为 \(P\) 。
若字符为 \(Q\),表示一个顾客的查询,后接三个整数 \(A,B,K\) \((1\leq{A}\leq{B}\leq{N})\) ,表示查询从第 \(A\) 书位到第 \(B\) 书位(包含 \(A\) 和 \(B\))中编码为 \(K\) 的书共多少本。
[!NOTE]
对于 \(100\%\) 的数据,\(1\leq{N},M\leq{10^5}\) ,所有出现的书的编码为不大于 \(2^{31}−1\) 的正整数。
思路
因为涉及到区间查询,考虑到使用分块。
对于 \(C\) 操作,找到对应的区间位置,消除原有数字影响,再维护区间,时间复杂度为 \(O(1)\) 。
对于 \(Q\) 操作,直接使用分块的查询,时间复杂度为 \(O(\sqrt{n})\) 。
注意到
所有出现的书的编码为不大于 \(2^{31}−1\) 的正整数。
直接开 \(2^{31}\) 的数组会 \(MLE\) 。
但是 \(N,M\leq{10^5}\) ,所以不同的编码数小于等于 \(N+M\) ,而且区间查询时不关心数字的大小关系,所以想到使用 \(map\) 进行存贮。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,d,a[N],id[N],qk[350][N],cnt=0;
map<int,int> mp;
void add(int p,int x){
if(!mp[x]){
mp[x]=++cnt;
}
qk[id[p]][mp[a[p]]]--;
a[p]=x;
qk[id[p]][mp[a[p]]]++;
}
int query(int l,int r,int c){
int sum=0;
for(int i=l;i<=min(r,id[l]*d);i++){
if(a[i]==c){
sum++;
}
}
if(id[l]!=id[r]){
for(int i=(id[r]-1)*d+1;i<=r;i++){
if(a[i]==c){
sum++;
}
}
}
for(int i=id[l]+1;i<=id[r]-1;i++){
sum+=qk[i][mp[c]];
}
return sum;
}
int main(){
cin>>n>>m;
d=sqrt(n);
for(int i=1;i<=n;i++){
cin>>a[i];
if(!mp[a[i]]){
mp[a[i]]=++cnt;
}
id[i]=(i-1)/d+1;
qk[id[i]][mp[a[i]]]++;
}
while(m--){
char op;
int l,r,k;
cin>>op>>l>>r;
if(op=='C'){
add(l,r);
}
else{
cin>>k;
cout<<query(l,r,k)<<endl;
}
}
return 0;
}
完结撒花!!!

浙公网安备 33010602011771号