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 的工作有两类:

  1. 图书馆经常购置新书,而书架任意时刻都是满的,所以只得将某位置的书拿掉并换成新购的书。
  2. 小 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;
}

完结撒花!!!

posted @ 2025-07-09 20:47  liyuan2023  阅读(12)  评论(0)    收藏  举报