分块算法

分块算法

首先来谈谈什么是分块呢?直接理解就是把一个整体分成若干个部分,这就是所谓的字面理解分块。

就如刚才所说,这就是分块的思想,而分块算法又称优雅的暴力

好啦,现在我们正式来理解分块算法......

 

一般来说,分块吗?你总要知道自己每块要分的大小对吧。这个已经解决了,一般每块都是分为sqrt(n)的大小,而一共有n / sqrt(n)块,当然,如果不能整除的话,你需要分的数量还是要加一的。之后你每块都要有一个标记吧,比如说:你有1,2,3,4,5这5个数,每块的大小是2, 一共3块, 其中 1 和 2 属于一块,3 和 4 属于一块,依次类推。一般存在一个belong[] 数组里面,方便后续操作。嘻嘻...你以为这样就完了吗?那你就错了,还需要一样东西,就是你需要记录每一块的范围,放心,这个很简单的,就是定义两个数组,分别记录在当前块所在范围的左端点和右端点。这个很容易实现的,就是上一个区间的右端点加一,和当前区间的右端点就是所求的范围。是不是有点晕,好吧。我们看一下代码吧,这样便于理解。

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int a[maxn]; //a数组存取原始数据 int belong[maxn]; //belong数组表示每个数属于哪一块方便调用 int L[1010]; //L和R表示各块左右端点 int R[1010]; int block,num; //block各块大小,num块数量 //修改,视情况而定 void change(int l, int r, int add) { //略..(可见下面模板题) } //查询,同上 int query(int l, int r) { //略.. } //建立各块(各个分块这个操作大致一样) void build(int n) { block = sqrt(n);//每块的大小 num = n / block; //一共有多少块 if (n % block) { num++; //如果不整除显然数量加个1 } for(int i = 1; i <= num; i++) { L[i] = (i - 1) * block + 1; //上一个区间的右端点加一就是当前区间的左端点 R[i] = i * block; //直接计算当前区间的右端点 } R[num] = n; //最后一个右端点一定是结尾 for(int i = 1; i <= n; i++) { belong[i] = (i - 1) / block + 1; //belong数组 } //初始状态维护......(省略) }
int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } build(n); //询问......(省略) }

 

posted @ 2019-07-20 20:42  不会fly的pig  阅读(867)  评论(7编辑  收藏  举报