介绍下简单的分块:

当我们遇到区间类问题的时候,如何保证我们快速而高效地完成操作?

答案是线段树分块。

所谓分块,就是把一个序列分成许多块分别维护。是不是想起了树状数组 这样能大大提高效率:

例如,我们需要查询l,r中所有元素的和

利用分块,我们可以把1 2 3 4 5 6 7 8 9 10

分为

[1 2 3] [4 5 6] [7 8 9] [10]

比如,我想要3~10的元素和。这是,我们拿出3~10的区间:

...[3] [4 5 6] [7 8 9] [10]

而我们已经预处理了 [4 5 6]与 [7 8 9]的区间和,我们只需要算出两端的和就可以。这样,就可以大大提高查询的速度。

#include <cstdio>
#include <cmath>
#include <algorithm> using namespace std; const int MaxN = 100010, MaxB = 1010; int n, B, q, Cnt;
int a[MaxN], Left[MaxB], Right[MaxB], Pos[MaxN];
long long sum[MaxN]; int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
// 分块预处理
B = max((int)sqrt(n), 1);
for (int i = 1; i <= n; i++)
{
if (i % B == 1 % B) Cnt++; // 每块块首 Cnt++
Pos[i] = Cnt; // i 处在哪一块
if (Left[Cnt] == 0) Left[Cnt] = i; // 第Cnt块的左边
Right[Cnt] = i; // 第Cnt块的右边
} // for (int i = 1; i <= n; i++) printf("%d ", Pos[i]); puts("");
// for (int i = 1; i <= Cnt; i++) printf("%d %d\n", Left[i], Right[i]); for (int i = 1; i <= Cnt; i++)
for (int j = Left[i]; j <= Right[i]; j++)
sum[i] += a[j]; // sum[i] 表示的是第i块的和 // 处理询问
scanf("%d", &q);
// a[l] + a[l + 1] + ... + a[r] 变成 sum[r] - sum[l - 1]
// 这样我们可以只用求 l=1 的情况
// 但是我现在不这样做
for (int i = 1; i <= q; i++)
{
int l, r;
scanf("%d %d", &l, &r);
long long ans = 0;
if (Pos[l] == Pos[r])
{
// 1 l,r 在同一个块内
// [ l r ]
for (int j = l; j <= r; j++) ans += a[j];
}
else
{
// 2 l,r 不在同一个块内
// [ l ] [ ] [ ] [r ]
for (int j = l; j <= Right[Pos[l]]; j++) ans += a[j];
for (int j = Right[Pos[l]] + 1; j <= Left[Pos[r]] - 1; j++) ans += sum[j];
for (int j = Left[Pos[r]]; j <= r; j++) ans += a[j];
}
printf("%lld\n", ans);
}
return 0;
}

(不是我写的,但是的确十分简洁易懂对吧)

例题:luogu P3203,LCT板子题可是可以用分块来过

#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<map>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<set>
#include<cstring>
using namespace std;
typedef long long ll;
const ll INF=;
const int MaxN = ;
int a[MaxN];
struct nd{
int t,to;//弹几次出此块
int from;//属于第几个块 }t[MaxN];
int n,m,I,J;
int sqr,cnt = -;
int Left[MaxN],Right[MaxN]; void findT(int x,int right,int &t,int &to){
int re = ;
int i = x;
for(;i <= right;){
int ad = a[i];
i += ad;
re++; }
t = re;
to = i;
//printf("需要%d步跳出,跳到%d\n",t,to); } inline int Max(int a,int b){
if(a>b) return a;
return b; } int main()
{
//freopen("testdata.in","r",stdin);
//freopen("testdata.out","w",stdout);
scanf("%d",&n);
for(int i = ;i < n; i++){
scanf("%d",&a[i]); } sqr = Max(sqrt(n),); /*for(int i = 0;i < n; i++){
if(i%sqr == 0%sqr) {
cnt++;
Left[cnt-1] = i;
//printf("第%d个块左边是%d\n",cnt-1,i);
}
Right[cnt-1] = i;
t[i].from = cnt-1;
//printf("右边界:%d\n",sqr*cnt-1);
findT(i,sqr*cnt-1,t[i].t,t[i].to); }*/ for(int i = ;i < n; i++){
if(i%sqr == %sqr){
Left[++cnt] = i; }
t[i].from = cnt;
Right[cnt] = i;
} for(int i = n-;i >= ;i--){
t[i].to = i+a[i];
if(t[i].to >= Right[t[i].from]) t[i].t = ;
else t[i].t=t[t[i].to].t+,t[i].to=t[t[i].to].to;
//printf("%d\n",t[i].to);
}
/*
for(int i = 0;i < n; i++){
printf("第%d个元素:跳%d次跳出此块(%d~%d)到%d,属于第%d个块\n",i,t[i].t,Left[t[i].from],Right[t[i].from],t[i].to,t[i].from);
}*/
scanf("%d",&m);
for(int i = ;i < m; i++){
scanf("%d%d",&I,&J);
int k;
if(I == ){ scanf("%d",&k);
a[J] = k;
for(int j = Right[t[J].from];j >= Left[t[J].from]; j--){
t[j].to = j+a[j];
if(t[j].to >= Right[t[J].from]) t[j].t = ;
else t[j].t=t[t[j].to].t+,t[j].to=t[t[j].to].to; }
}
else{
int ans = ;
while(J < n){
ans += t[J].t;
J = t[J].to; }
printf("%d\n",ans); } } return ;
}

P3203

利用分块思想,每一个元素维护跳几次跳出这个块以及跳到哪里。

这样,就可以大大提高查询的速度,但是问题在于如何O(n)的预处理。

预处理:从后往前枚举,就好像穿起一条链。比如:

设t[i]为需要跳t[i]次跳出某个块,to[i]为跳出某个块到to[i]。

假设这个序列为:

... 1 1

第n个元素,处于第x块,则需要1次跳出块到n+a[i]。(t[i] = 1,to[i] = 4)

第n-1个元素,处于第x块(假设处于同一个块),则需要2次跳出块到4。(t[i] = t[to[i]]+1 = 2,to[i] = to[to[i]],相信不难理解)

以此类推。

这样,只要在修改的时候对于修改元素所在的块进行我们写好的预处理。

【OI】简单的分块的更多相关文章

  1. HYSBZ 2957 分块

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2957 题意:中文题面 思路: 来自此博客 首先明确问题,对于每栋楼房的斜率K=H/X,问题 ...

  2. [BZOJ 2957]楼房重建(THU2013集训)(分块思想)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2957 分析: 首先明确问题,对于每栋楼房的斜率K=H/X,问题就是问有多少个楼房的K比前面所有 ...

  3. P3203 [HNOI2010]弹飞绵羊 —— 懒标记?分块?LCT?...FAQ orz

    好久没写博客了哈,今天来水一篇._(:з」∠)_ 题目 :弹飞绵羊(一道省选题) 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏 ...

  4. P3203 [HNOI2010]弹飞绵羊 —— 懒标记?分块?

    好久没写博客了哈,今天来水一篇._(:з」∠)_ 题目 :弹飞绵羊(一道省选题) 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏 ...

  5. 分块基础练习 UESTC 1324

    http://acm.uestc.edu.cn/#/problem/show/1324 思路:基础分块,这个是一个特别简单的分块,就当做是一个练习了.然后这题也是很简单的单点线段树更新. //看看会不 ...

  6. [luogu3203 HNOI2010] 弹飞绵羊 (分块)

    传送门 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置, ...

  7. NLP(六) 分块、句法分析、依存分析

    内置分块器 分块:从文本中抽取短语 import nltk text = 'Lalbagh Botanical Garden is a well known botanical garden in B ...

  8. Codechef TRIPS Children Trips (分块、倍增)

    题目链接: https://www.codechef.com/problems/TRIPS 感觉CC有点毒瘤啊.. 题解: 首先有一个性质可能是因为太傻所以网上没人解释,然而我看了半天: 就是正序和倒 ...

  9. HTTP 协议中的 Content-Encoding 和 Transfer-Encoding(内容编码和传输编码)

    转自:http://network.51cto.com/art/201509/491335.htm Transfer-Encoding,是一个 HTTP 头部字段,字面意思是「传输编码」.实际上,HT ...

随机推荐

  1. vue 轮播插件使用

    <template> <div> <Swiper ref="swiper" v-if="list.length > 0" : ...

  2. 样例GeoQuiz应用开发 第2章

    先介绍一下MVC,Model View Controller,是软件架构中最常见的一种框架. 简单来说就是通过 controller 的控制去操作 model 层的数据,并且返回给 view 层展示, ...

  3. 零基础入门学习Python(14)--字符串:各种奇葩的内置方法

    前言 这节课我们回过头来,再谈一下字符串,或许我们现在再来谈字符串,有些朋友可能觉得没必要了,甚至有些朋友就会觉得,不就是字符串吗,哥闭着眼也能写出来,那其实关于字符串还有很多你不知道的秘密哦.由于字 ...

  4. 版本控制git之五-标签管理 tags 标签 代码版本 如: v1.0

      版本控制git之五-标签管理 打标签 像其他版本控制系统(VCS)一样,Git 可以给历史中的某一个提交打上标签,以示重要. 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等等). ...

  5. jmeter 接口测试

    web接口测试工具: 手工测试的话可以用postman ,自动化测试多是用到 Jmeter(开源).soupUI(开源&商业版). 下面将对前一篇Postman做接口测试中的接口用Jmeter ...

  6. LeetCode(6) ZigZag Conversion

    题目 The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows li ...

  7. 【XML】-- C#读取XML中元素和属性的值

    Xml是扩展标记语言的简写,是一种开发的文本格式. 啰嗦几句儿:老师布置的一个小作业却让我的脑细胞死了一堆,难的不是代码,是n多嵌套的if.foreach,做完这个,我使劲儿想:我一女孩,没有更多女孩 ...

  8. 【04】emmet系列之编辑器

     [01]emmet系列之基础介绍 [02]emmet系列之HTML语法 [03]emmet系列之CSS语法 [04]emmet系列之编辑器 [05]emmet系列之各种缩写 前端开发人员,常用的是s ...

  9. 九度oj 题目1490:字符串链接

    题目1490:字符串链接 时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:2610 解决:1321 题目描述: 不用strcat 函数,自己编写一个字符串链接函数MyStrcat(char ...

  10. 7-9 旅游规划(25 分)(Dijkstra最短路径算法)

    有了一张自驾旅游路线图,你会知道城市间的高速公路长度.以及该公路要收取的过路费.现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径.如果有若干条路径都是最短的,那么需要输出最便 ...