骗分大法之-----分块||迷之线段树例题a
什么是分块呢?
就是一种可以帮你骗到不少分的神奇的算法。
分块的写法有几种,我所知道的有①预处理②不预处理
不预处理的代码我看得一脸懵逼
所以我在这里就谈一下预处理的版本www
首先看一道题:
给定一个包含n个数的序列,初值全为0,现对这个序列有两种操作:
操作1:把 给定 第k1 个数改为k2;
操作2:查询 从第k1个数到第k2个数得最大值。(k1<=k2<=n)
所有的数都 <=100000
好的,如果我们搞遍历肯定超时到爆炸。
那么就要用到分块大法了
把这n个数分成若干块,然后每个块计算出最值,并存入数组。
这样在查询的时候只需要遍历所有块的个数,效率++
下面引用梓轩学姐的神奇讲解:
想象一下你现在是一个项目的主管,你要高效地管理所有的员工,那么一个最容易想到的方法就是将他们分组,然后每个组定一个组长。
现在你要询问某些人的最大值,那么如果一个组的所有员工都在询问的范围内,你只需要询问这个组的组长一次就可以知道这个组最厉害的员工是谁而不是一个一个询问,而如果有些组只有其中几个人被询问,那么你还要一个一个地问这几个人。
现在我们把这种思想搬到序列上,很容易就能想到将相邻的元素分到同一个组,也就是我们所说的分块。那么对于询问某个区间,你只需要将这个区间分成若干个完整的块并且记录每个块的最大值,以及两头的若干单独的元素。举个栗子:你有20个元素,你将它们每四个元素分一块,也就是分成了[1,4][5,8][9,12][13,16][17,20]五个块,此时当你询问[6,18]这个区间时只需要询问第6、7、8、17、18个数和第三第四个块的最大值即可,这样我们就免去了一个一个访问中间的元素。
至于修改操作则比较简单,当修改一个元素时,如果它的值增大了,那么我们判断它是否比之前的最大值还大就好,而当被修改的元素是块内的最大值而且它的数值还减小了则比较麻烦,我们只能通过再次遍历一遍整个块来确定最大值。
此时我们来考虑要怎么分块才能更高效地完成工作,如果一个块元素太多那么你要一个一个访问的元素可能很多(比如一个很大的块只有一个元素没被询问到那你得访问遍这整个块除了它以外的元素),如果一个块元素太少那么你可能会要访问好多组。
我们假定S为块的大小,即相邻的每S个元素分为一块,那么我们最多分n/S+1块,假设块的个数是C(很显然它和n/S几乎等价),再来看我们的询问操作是如何进行的:访问所有被询问区间整个包含的块,以及两端的两个不被整个包含的块(可能没有)的被询问的若干元素。前半部分我们会访问O(C)个块,而后半部分我们会访问O(S)个元素。接着还要看修改操作:最坏的情况下我们需要访问整个块,也就是O(S)。
由于O(a+b)=O(max(a,b)),而C是随S递减的,当C=S时才能得到最好的复杂度,也即是S=n^0.5次方。那么一次操作是O(n^0.5)的代价,整个算法的复杂度也就是O(m*n^0.5),由于m和n是同阶的,所以说O(n^1.5)(读作欧恩根号恩)也可以。我们可以看到,只有根号才能让块的元素个数和块的个数达到了均衡,这也就是为什么分块的标志是根号的元素。
回顾整个过程其实非常简单:将序列分块,然后将一个区间询问分解为若干个块和若干个单独元素即可。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
然后,是例题的代码↓:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int maxx=,inf=;
int n=,s=,c=,k=,q=,w=;
int a[maxx],f[maxx];
int mx[],zuo[],you[];
void chu()
{
s=(int)sqrt((double)n);
for(int i=;i<n;i+=s)
{
f[i]=++c;
for(int j=i+;j<=i+s-;j++)
{
f[j]=f[i];
}
zuo[c]=i;
you[c]=i+s-;
}
if(s>)
if(n%s>)
{
zuo[c+]=you[c]+;
you[++c]=n;
for(int i=zuo[c];i<=you[c];i++) f[i]=c;
} }
void gai(int x,int v)
{
int y=f[x];
a[x]=v;
int temp=-*inf;
for(int i=zuo[y];i<=you[y];i++)
if(a[i]>temp)
temp=a[i]; mx[y]=temp;
}
int zui(int l,int r)
{
int x=f[l],y=f[r],ans=-inf;
if(x==y)
{
for(int i=l;i<=r;i++)
if(a[i]>ans)
ans=a[i];
return ans;
}
for(int i=l;i<=you[x];i++)
if(a[i]>ans)
ans=a[i];
for(int i=x+;i<y;i++)
if(mx[i]>ans)
ans=mx[i];
for(int i=zuo[y];i<=r;i++)
if(a[i]>ans)
ans=a[i];
return ans;
}
int main()
{
memset(a,,sizeof(a));
memset(f,,sizeof(f));
memset(mx,,sizeof(mx));
cin>>n;
chu();
for(int i=;i<=n;i++)
{
cin>>k>>q>>w;
if(k==) gai(q,w);
if(k==) cout<<zui(q,w)<<endl;
}
return ;
}
骗分大法之-----分块||迷之线段树例题a的更多相关文章
- ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)
题意 链接:https://nanti.jisuanke.com/t/A1998 给出一个有根树(根是1),有n个结点.初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L(根 ...
- 分块+lazy 或者 线段树+lazy Codeforces Round #254 (Div. 2) E
E. DZY Loves Colors time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- 【2018沈阳赛区网络预选赛J题】Ka Chang【分块+DFS序+线段树】
题意 给出一个有根树(根是1),有n个结点.初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L的点的值全部增加X.操作2.查询以x为根的子树的结点值得和. 其中N,Q< ...
- 【分块】【线段树】bzoj3212 Pku3468 A Simple Problem with Integers
线段树入门题…… 因为poj原来的代码莫名RE,所以丧病地写了区间修改的分块…… 其实就是块上打标记,没有上传下传之类. #include<cstdio> #include<cmat ...
- HDU - 4366 Successor DFS序 + 分块暴力 or 线段树维护
给定一颗树,每个节点都有忠诚和能力两个参数,随意指定一个节点,要求在它的子树中找一个节点代替它,这个节点要满足能力值大于它,而且是忠诚度最高的那个. 首先,dfs一下,处理出L[i], R[i]表示d ...
- BZOJ 4491 分块OR差分+线段树
思路: (是不是只有我作大死写了个分块) up[i][j]表示从第i块开始到第j个位置 上升的最大值 down[i][j]同理 left_up[i]表示从第i块开始能够上升的最长长度 left_dow ...
- 【对询问分块】CODEVS1080 线段树练习
#include<cstdio> #include<cmath> using namespace std; #define N 100001 int sum[N],a[N],n ...
- luoguP5105 不强制在线的动态快速排序 [官方?]题解 线段树 / set
不强制在线的动态快速排序 题解 算法一 按照题意模拟 维护一个数组,每次直接往数组后面依次添加\([l, r]\) 每次查询时,暴力地\(sort\)查询即可 复杂度\(O(10^9 * q)\),期 ...
- [CSP-S模拟测试]:Weed(线段树)
题目描述 $duyege$的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹.为了查出真相,$duyege$准备修好电脑之后再进行一次金坷垃的模拟实验.电脑上面有若干层金坷垃,每次只能在上面撒上一层高度 ...
随机推荐
- Helm 入门安装指南
Helm 是 Kubernetes 生态系统中的一个软件包管理工具.本文将介绍 Helm 中的相关概念和基本工作原理,并通过一个具体的示例学习如何使用 Helm 打包.分发.安装.升级及回退 Kube ...
- css (具体代码看笔记本)
参考:https://www.cnblogs.com/liwenzhou/p/7999532.html 1. CSS语法 选择器 {属性1:值1;...;} 2. CSS导入方式 1. 行 ...
- 《GPU高性能编程CUDA实战》第十一章 多GPU系统的CUDA C
▶ 本章介绍了多设备胸膛下的 CUDA 编程,以及一些特殊存储类型对计算速度的影响 ● 显存和零拷贝内存的拷贝与计算对比 #include <stdio.h> #include " ...
- 0_Simple__simplePitchLinearTexture
对比设备线性二维数组和 CUDA 二维数组在纹理引用中的效率 ▶ 源代码.分别绑定相同大小的设备线性二维数组和 CUDA 二维数组为纹理引用,做简单的平移操作,重复若干次计算带宽和访问速度. #inc ...
- EXCEL 数组公式
数组里的元素,同一行内的各元素用英文逗号“,”分开,用英文分号“;”将各行分开 3.单列数组与单行数组的计算 两个数组相加,查看结果是几行几列:在任意单元格输入公式“=A80:A83+B87:E87” ...
- VB6单片机编程中的汉字处理
在DOS时代,拥有一个华丽的汉字菜单几乎是每个高档中文应用程序必须的包装.中文Windows操作系统的出现使得高级开发平台实现全中文的提示和界面非常容易和方便.在一般的应用程序中已经很少需要去专门考虑 ...
- UI5-文档-4.6-Modules
在SAPUI5中,资源通常被称为模块.在这一步中,我们将上次练习中的警报替换为sap.m库中的适当消息Toast.所需的模块可以异步加载. Preview A message toast displa ...
- tensorflow笔记之学习率设置
在使用梯度下降最小化损失函数时,如果学习率过大会导致问题不能收敛到最优解,学习率过小,虽然可以收敛到最优解,但是需要的迭代次数会大大增加,在Tensorflow中,可以用指数衰减法设置学习率,tf.t ...
- linux配置裸设备
1.什么裸设备?字符设备?块设备? 裸设备:也叫裸分区(原始分区),是一种没有经过格式化,不被Unix/Linux通过文件系统来读取的特殊字符设备.它由应用程序负责对它进行读写操作.不经过文件系统的缓 ...
- 如何将String转换为int
1. int i = Integer.parseInt([String]); 或 i = Integer.parseInt([String],[int radix]); Integer.parseIn ...