分块思想

今天学习了一个算法(这个应该叫做算法吧?)叫做分块(和莫队,但是莫队还没有搞懂,搞懂再来写吧)
听起来很高级,蒟蒻表示瑟瑟发抖。但是学完发现怎么那么像是一种变相的暴力呢。
分块思想:假如你要处理一个很长区间上的问题,并且有很多个查询(以及修改),暴力显然已经不可行了。但是暴力效率低下的主要原因是因为他没有很好的利用每次处理后得到的信息而选择重新处理,而进行优化的关键就是如何有效的储存每次处理后的信息。对于线段树来讲是将这个区间进行好多次二分变成一个树进行储存,大区间就储存着每次处理后的信息从而提升效率,对于树状数组来说它同样是将区间分成了许多小部分,用的不是二分而是对二进制的一种应用形成的树状结构。而我们能不能什么高级的数据结构都不使用来解决这种问题呢?答案就是朴素的分块思想——如果区间比较大,就分成一个一个小段来处理,用一个数组来保存每一个小段的信息,然后在具体询问的时候如果询问的区间大于我们分的块就能够使用我们保存过的数据提高效率,如果小于就直接暴力应该也不会很大。如果大于我们分的块但又不是整块怎么办呢?就将两端不是整块的进行暴力,应该也不会很大(至少可以接受)
这里附一道比较有趣的分块题(我做的第一道分块题):BZOJ2002
题意大概是你有一只绵羊(不要问我为什么是只羊而不是兔子),然后它可以在许多弹簧上跳,现在给你在每个弹簧上能够向后跳多远,问你它跳多少次后绵羊就掉下去。而且还会修改弹簧的弹力。
对于这个问题很容易有一个暴力的思想就是我们对于每次询问就直接让他跳就好了,每次修改就改就好了,显然会爆。
有一种比较巧妙的从后往前跳一边然后储存这个信息以后就能直接使用(从后往前是因为他是向后跳的,所以只会被后面的值影响),但是每次修改又会变成一个比较复杂的问题。
所以我们折中的使用分块,就是将原来的大区间分成许多小区间(一般来讲是sqrt(n)不要问我为什么,我也不知道,好像是什么基本不等式推出来比较好),然后每次更新小区间的值,查询的时候每次用小区间的值。
具体的做法是用两个数组,一个储存跳出当前块需要多少步(求答案的时候直接加起来),一个储存跳出这个块后会跳到下个块的什么位置。从后往前进行初始化。然后对于每次更新只在块内更新,对块外的没有影响。
详细看注释:

#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#define belong(x) ((x-1)/block+1)
using namespace std;const int maxn=200005;
int n,m,block;
int a[maxn],pos[maxn],step[maxn];int ask(int x)
{int ans=0;while(x!=-1){ans+=step[x];x=pos[x];}return ans;
}
int main()
{memset(a,0,sizeof(a));memset(pos,0,sizeof(pos));memset(step,0,sizeof(step));scanf("%d",&n);block=(int)sqrt(n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=n;i>0;i--)	//从后往前初始化{if(i+a[i]>n){pos[i]=-1; step[i]=1;	//如果直接跳出整个区间了标记位置为-1}else if(i+a[i]>belong(i)*block){pos[i]=i+a[i]; step[i]=1;	//记录跳到下一个块的什么位置}else{		//如果没有跳出去就会一直跳到i+a[i]跳出去的位置,用的步数等于i+a[i]用的步数+1pos[i]=pos[i+a[i]];	step[i]=step[i+a[i]]+1;}}scanf("%d",&m);int cmd,u,v;for(int i=0;i<m;i++){scanf("%d",&cmd);if(cmd==1){scanf("%d",&u);u++;printf("%d\n",ask(u)); }else if(cmd==2){scanf("%d%d",&u,&v);u++;	//我们这里是从1开始的,而问题是从0开始的,请注意a[u]=v;int left=(belong(u)-1)*block;for(int i=u;i>left;i--){if(i+a[i]>n){pos[i]=-1;step[i]=1;}else if(i+a[i]>belong(i)*block){pos[i]=i+a[i];step[i]=1;}else{pos[i]=pos[i+a[i]];step[i]=step[i+a[i]]+1;}}}}return 0;
}

就酱 ^_ ^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384214.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零开始学C++之STL(八):函数对象、 函数对象与容器、函数对象与算法

http://blog.csdn.net/jnu_simba/article/details/9500219 一、函数对象 1、函数对象&#xff08;function object&#xff09;也称为仿函数&#xff08;functor&#xff09; 2、一个行为类似函数的对象&#xff0c;它可以没有参数&#xff0c;也可以带有若干参数。 3、任何重载…

树状数组初步理解

学习树状数组已经两周了&#xff0c;之前偷懒一直没有写&#xff0c;赶紧补上防止自己忘记&#xff08;虽然好像已经忘得差不多了&#xff09;。 作为一种经常处理区间问题的数据结构&#xff0c;它和线段树、分块一样&#xff0c;核心就是将区间分成许多个小区间然后通过对大区…

命名函数

函数体是代码块 代码块do...end是一种表达式的组织方式。 # ./times.exs下defmodule Times dodef doule(n) don * 2end end 函数调用与模式匹配 代码如下&#xff1a; # ./factorial.exs    计算阶层 defmodule Factorial dodef of(0), do: 1          #终止条件…

STL运用的C++技术(6)——函数对象

http://blog.csdn.net/wuzhekai1985/article/details/6658940?_t_t_t0.20427969420870595 STL是C标准库的重要组成部分之一&#xff0c;它不仅是一个可复用的组件库&#xff0c;更是一个包含算法与数据结构的软件框架&#xff0c;同时也是C泛型编程的很好例子。STL中运用了许多…

列表与递归

头部和尾部 [head | tail ] [1] #head 1 tail [] [head | tail ] [1, 2, 3] #head 1 tail [2, 3] [head | tail ] [] #报错 创建映射函数 我们可以使用一个函数来处理列表中的各个元素&#xff0c;如此可以接受更加复杂的处理&#xff0c;也可以…

优先队列小结

不像栈和队列&#xff0c;虽然STL有较好实现但是我们自己也可以很方便的实现&#xff0c;优先队列自己实现起来就比较复杂&#xff0c;比较浪费时间&#xff08;而且自己目前也不会233&#xff09;而优先队列因为其较好的特性经常被使用&#xff0c;因此对它的熟练掌握是做题的…

字典:散列表、散列字典、关键字列表、集合与结构体

字典 散列表和散列字典都实现了Dict的行为。Keyword模块也基本实现了&#xff0c;不同之处在于它支持重复键。 Eunm.into可以将一种类型的收集映射转化成另一种。 defmodule Sum dodef values(dict) dodict |> Dict.values |> Enum.sumend endhd [ one: 1, two: 2, thre…

C++11 学习笔记 lambda表达式

http://blog.csdn.net/fjzpdkf/article/details/50249287 lambda表达式是C11最重要也最常用的一个特性之一。lambda来源于函数式编程的概念&#xff0c;也是现代编程语言的一个特点。 一.函数式编程简介 定义&#xff1a;简单说&#xff0c;“函数式编程”是一种“编程范式”。…

Cutting Codeforces Round #493 (Div. 2)

Cutting There are a lot of things which could be cut — trees, paper, “the rope”. In this problem you are going to cut a sequence of integers. There is a sequence of integers, which contains the equal number of even and odd numbers. Given a limited bud…

Enum、Stream

Enum 其常见用法见&#xff1a;https://cloud.tencent.com/developer/section/1116852 在sort时&#xff0c;如果要获得稳定的排序结果&#xff0c;要使用< 而不是 <。 Stream Stream是延迟处理的&#xff0c;而Enum是贪婪的&#xff0c;则意味着传给它一个收集&#xff…

linux网络编程之posix 线程(三):posix 匿名信号量与互斥锁 示例生产者--消费者问题

http://blog.csdn.net/jnu_simba/article/details/9123603 一、posix 信号量 信号量的概念参见这里。前面也讲过system v 信号量&#xff0c;现在来说说posix 信号量。 system v 信号量只能用于进程间同步&#xff0c;而posix 信号量除了可以进程间同步&#xff0c;还可以线程间…

洛谷P1080-国王游戏-贪心+高精度

P1080-国王游戏 啊啊啊&#xff0c;刚才已经写了一次了&#xff0c;但是Edge浏览器不知道为什么卡住了&#xff0c;难受。 好吧&#xff0c;其实是一道可做题&#xff0c;分析得到的贪心策略就是就是将a * b小的放在前面&#xff08;其他的懒得说了&#xff09;&#xff0c;主要…

字符串与二进制

单引号字符串会被表示成整数值列表。 &#xff1f;c返回字符 c 的整数编码。下面这个例子用于解析字符列表表示法&#xff0c;该表示法用于表示一个任意的有符号的十进制数据。 defmodule Parse dodef number([ ?- | tail ]) do_number_digits(tail, 0) * -1enddef number([ ?…

P1092虫食算-深度优先搜索+玄学剪枝

P1092虫食算 这道题的思想并不复杂&#xff0c;可是难点在于各种玄学剪枝。在仔细研究了题解大佬的剪枝原理后终于氵了过去。 先上代码&#xff1a; #include<cstdio> #include<cstring> #include<algorithm> using namespace std;const int MAXN100; int n…

多进程

使用spawn创建一个新进程&#xff0c;其第一个参数是模块名、第二个参数是函数名、第三个参数是参数列表。spawn会返回一个进程标识符&#xff0c;通常叫做PID。 defmodule Spawn1 dodef greet doreceive do{sender, msg} ->send sender, { :ok, "Hello #{msg}" }…

Linux socket编程(二) 服务器与客户端的通信

http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html上一篇写了对套接字操作的封装&#xff0c;这一节使用已封装好的Socket类实现服务器与客户端的通信&#xff08;Socket的定义见上篇Socket.h) 服务器端&#xff1a; ServerSocket.h #ifndef SERVERSOCKET_H #defin…

OTP服务器

defmodule Sequence.Server douse GenServerdef handle_call( :next_number, _from, current_number) do{ :reply, current_number, current_number 1}  #reply告诉OTP将第二个元素返回给客户端end end use的效果将OTP GenServer的行为添加到当前模块。这样它就可以处理所有…

洛谷P1040-加分二叉树-dp+二叉树

P1040-加分二叉树 这道题放在深度优先搜索的训练题中&#xff0c;可是我实在没有看出来应该怎么搜索。看了题解以后才看出来是一个很简单的dp(我果然还是太菜了) 看出dp并且算出来最大的分数不是很复杂&#xff0c;关键是输出给定中序遍历序列的二叉树的先序遍历&#xff0c;要…

UNIX网络编程:I/O复用技术(select、poll、epoll)

http://blog.csdn.net/dandelion_gong/article/details/51673085 Unix下可用的I/O模型一共有五种&#xff1a;阻塞I/O 、非阻塞I/O 、I/O复用 、信号驱动I/O 、异步I/O。此处我们主要介绍第三种I/O符复用。 I/O复用的功能&#xff1a;如果一个或多个I/O条件满足&#xff08;输…

解决iex -S mix报错

执行iex -S mix命令的时候会遇到如下错误&#xff1a; 执行 mix deps.get 然后就可以运行 iex -S mix了 其中&#xff0c;有可能会出现 按照其网站下载相应文件&#xff0c;复制到项目根目录下&#xff0c;然后执行命令&#xff08;mix local.rebar rebar ./rebar&#xff09;即…