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号
浙公网安备 33010602011771号