LOJ数列分块入门九题(上)
一转眼,已经有整整一年没有在博客园写博客了。去洛谷写了几篇(How time flys.
最近突然想起其实我不太擅长分块算法,又想起去年暑假有位同学同我提起过LOJ的数列分块九题,说来惭愧,打了这么久题今天才打算做这个系列,甚至连LOJ的账号都没有注册。。。于是今天花费了半天时间敲题,但是更尴尬的是只打了前四题,分块细节真的是相当繁琐。
分块是一种优雅的暴力,时间复杂度为根号n量级,虽然同线段树树状数组之类的logn量级的复杂度无法相提并论,但是在大多数情况下,分块都可以比较好地替代线段树。其代码量较少且逻辑相较线段树而言更清晰尤其是可以进行块内二分之类的操作,从而有的时候比线段树更有优势。
分块,顾名思义,就是将数列分为多块进行考虑,在进行区间修改或者区间查询操作时,使用分块算法,我们可以直接处理区间中的块,再处理零散块。我们可以将数列划分为根号n个块,从而将时间复杂度降低至根号n。
#6277. 数列分块入门 1 - 题目 - LibreOJ (loj.ac)
区间加法,单点查值,分块水题(变量名想半天)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(5e4)+5;
ll a[maxn];
ll l[maxn];
ll r[maxn];
ll bel[maxn];
ll lazy_add[maxn];
void build(ll n){
ll block=sqrt(n);
ll num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
l[i]=(i-1)*block+1;
r[i]=min(n,i*block);
lazy_add[i]=0;
}
for(int i=1;i<=n;i++){
bel[i]=(i-1)/block+1;
}
}
void add(ll L,ll rr,ll c){
ll s=bel[L]+1;
ll t=bel[rr]-1;
for(int i=L;i<=min(rr,r[s-1]);i++){
a[i]+=c;
}
if(bel[L]==bel[rr])return;
for(int i=l[t+1];i<=rr;i++){
a[i]+=c;
}
for(int i=s;i<=t;i++){
lazy_add[i]+=c;
}
}
void calc(ll x){
ll p=bel[x];
for(int i=l[p];i<=r[p];i++){
a[i]+=lazy_add[p];
}
lazy_add[p]=0;
cout<<a[x]<<endl;
}
int main(){
ll n;
cin>>n;
build(n);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
ll opt,L,rr,c;
cin>>opt>>L>>rr>>c;
if(!opt){
add(L,rr,c);
}
else{
calc(rr);
}
}
return 0;
}
#6278. 数列分块入门 2 - 题目 - LibreOJ (loj.ac)
块内二分即可(线段树不行),注意边角的处理
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(5e4)+5;
int L[maxn],R[maxn];
int bel[maxn];
ll a[maxn];
ll b[maxn];
ll tmp[maxn];
ll tag[maxn];
void build(int n){
int block=sqrt(n);
int num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=min(n,i*block);
sort(a+L[i],a+R[i]+1);
for(int j=L[i];j<=R[i];j++){
bel[j]=i;
}
}
}
void update(int l,int r,ll c){
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++)b[i]+=c;
for(int i=L[bel[l]];i<=R[bel[l]];i++){
tmp[i]=b[i];
}
sort(tmp+L[bel[l]],tmp+R[bel[l]]+1);
for(int i=L[bel[l]];i<=R[bel[l]];i++){
a[i]=tmp[i];
}
}
else{
for(int i=l;i<=R[bel[l]];i++){
b[i]+=c;
}
for(int i=L[bel[l]];i<=R[bel[l]];i++){
tmp[i]=b[i];
}
sort(tmp+L[bel[l]],tmp+R[bel[l]]+1);
for(int i=L[bel[l]];i<=R[bel[l]];i++){
a[i]=tmp[i];
}
for(int i=L[bel[r]];i<=r;i++){
b[i]+=c;
}
for(int i=L[bel[r]];i<=R[bel[r]];i++){
tmp[i]=b[i];
}
sort(tmp+L[bel[r]],tmp+R[bel[r]]+1);
for(int i=L[bel[r]];i<=R[bel[r]];i++){
a[i]=tmp[i];
}
for(int i=bel[l]+1;i<bel[r];i++){
tag[i]+=c;
}
}
}
void calc(int l,int r,ll c){
ll ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(b[i]+tag[bel[l]]<c)ans++;
}
}
else{
for(int i=l;i<=R[bel[l]];i++){
if(b[i]+tag[bel[l]]<c)ans++;
}
for(int i=L[bel[r]];i<=r;i++){
if(b[i]+tag[bel[r]]<c)ans++;
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=lower_bound(a+L[i],a+R[i]+1,c-tag[i])-a-L[i];
}
}
cout<<ans<<endl;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i];
build(n);
for(int i=1;i<=n;i++){
ll opt,l,r,c;
cin>>opt>>l>>r>>c;
if(!opt){
update(l,r,c);
}
else{
calc(l,r,c*c);
}
}
return 0;
}
#6279. 数列分块入门 3 - 题目 - LibreOJ (loj.ac)
前一题修改一下即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(1e5)+5;
int L[maxn],R[maxn];
int bel[maxn];
ll a[maxn];
ll b[maxn];
ll tmp[maxn];
ll tag[maxn];
void build(int n){
int block=sqrt(n);
int num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=min(n,i*block);
sort(a+L[i],a+R[i]+1);
for(int j=L[i];j<=R[i];j++){
bel[j]=i;
}
}
}
void update(int l,int r,ll c){
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++)b[i]+=c;
for(int i=L[bel[l]];i<=R[bel[l]];i++){
tmp[i]=b[i];
}
sort(tmp+L[bel[l]],tmp+R[bel[l]]+1);
for(int i=L[bel[l]];i<=R[bel[l]];i++){
a[i]=tmp[i];
}
}
else{
for(int i=l;i<=R[bel[l]];i++){
b[i]+=c;
}
for(int i=L[bel[l]];i<=R[bel[l]];i++){
tmp[i]=b[i];
}
sort(tmp+L[bel[l]],tmp+R[bel[l]]+1);
for(int i=L[bel[l]];i<=R[bel[l]];i++){
a[i]=tmp[i];
}
for(int i=L[bel[r]];i<=r;i++){
b[i]+=c;
}
for(int i=L[bel[r]];i<=R[bel[r]];i++){
tmp[i]=b[i];
}
sort(tmp+L[bel[r]],tmp+R[bel[r]]+1);
for(int i=L[bel[r]];i<=R[bel[r]];i++){
a[i]=tmp[i];
}
for(int i=bel[l]+1;i<bel[r];i++){
tag[i]+=c;
}
}
}
void calc(int l,int r,ll c){
ll ans=-1e9;
bool fg=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(b[i]+tag[bel[l]]<c)ans=max(ans,b[i]+tag[bel[l]]),fg=1;
}
}
else{
for(int i=l;i<=R[bel[l]];i++){
if(b[i]+tag[bel[l]]<c)ans=max(ans,b[i]+tag[bel[l]]),fg=1;
}
for(int i=L[bel[r]];i<=r;i++){
if(b[i]+tag[bel[r]]<c)ans=max(ans,b[i]+tag[bel[r]]),fg=1;
}
for(int i=bel[l]+1;i<bel[r];i++){
int p=lower_bound(a+L[i],a+R[i]+1,c-tag[i])-a-1;
if(a[p]+tag[i]<c)ans=max(ans,a[p]+tag[i]),fg=1;
}
}
if(fg)cout<<ans<<endl;
else cout<<-1<<endl;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i];
build(n);
for(int i=1;i<=n;i++){
ll opt,l,r,c;
cin>>opt>>l>>r>>c;
if(!opt){
update(l,r,c);
}
else{
calc(l,r,c);
}
}
return 0;
}
#6280. 数列分块入门 4 - 题目 - LibreOJ (loj.ac)
区间加法,区间求和(经典线段树,不过也可以分块)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(1e5)+5;
ll a[maxn];
int L[maxn],R[maxn];
int bel[maxn];
ll siz[maxn];
ll tag[maxn];
void build(int n){
int block=sqrt(n);
int num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=min(n,i*block);
for(int j=L[i];j<=R[i];j++){
bel[j]=i;
siz[i]+=a[j];
}
}
}
void update(int l,int r,ll c){
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
a[i]+=c;
siz[bel[l]]+=c;
}
}
else{
for(int i=l;i<=R[bel[l]];i++){
a[i]+=c;
siz[bel[l]]+=c;
}
for(int i=L[bel[r]];i<=r;i++){
a[i]+=c;
siz[bel[r]]+=c;
}
for(int i=bel[l]+1;i<bel[r];i++){
siz[i]+=(R[i]-L[i]+1)*c;
tag[i]+=c;
}
}
}
void calc(int l,int r,ll c){
ll ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
ans=(ans+a[i]+tag[bel[l]])%c;
}
}
else{
for(int i=l;i<=R[bel[l]];i++){
ans=(ans+a[i]+tag[bel[l]])%c;
}
for(int i=L[bel[r]];i<=r;i++){
ans=(ans+a[i]+tag[bel[r]])%c;
}
for(int i=bel[l]+1;i<bel[r];i++){
ans=(ans+siz[i])%c;
}
}
cout<<ans%c<<endl;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
build(n);
for(int i=1;i<=n;i++){
ll opt,l,r,c;
cin>>opt>>l>>r>>c;
if(!opt){
update(l,r,c);
}
else calc(l,r,c+1);
}
return 0;
}
LOJ数列分块入门九题(上)的更多相关文章
- LOJ 数列分块入门 9 题解题报告
LOJ 数列分块入门 9 题解题报告 \(\text{By DaiRuiChen007}\) I. 数列分块入门 1 题目大意 \(\text{Link}\) 维护一个长度为 \(n\) 的序列,支持 ...
- 数列分块入门九题(三):LOJ6283~6285
Preface 最后一题我一直觉得用莫队是最好的. 数列分块入门 7--区间乘法,区间加法,单点询问 还是很简单的吧,比起数列分块入门 7就多了个区间乘. 类似于线段树,由于乘法的优先级高于加法,因此 ...
- 数列分块入门九题(二):LOJ6280~6282
Preface 个人感觉这中间的三题是最水的没有之一 数列分块入门 4--区间加法,区间求和 这个也是很多数据结构完爆的题目线段树入门题,但是练分块我们就要写吗 修改还是与之前类似,只不过我们要维护每 ...
- 数列分块入门九题(一):LOJ6277~6279
Preface 分块,一个神奇的暴力算法.可以把很多\(O(n^2)\)的数据结构题的暴力优化到常数极小的\(O(n\sqrt n)\).当一些毒瘤题无法用线段树,主席树,平衡树,树状数组...... ...
- [Loj] 数列分块入门 1 - 9
数列分块入门 1 https://loj.ac/problem/6277 区间加 + 单点查询 #include <iostream> #include <cstdio> #i ...
- loj 数列分块入门 5 7 8
5 题意 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间开方,区间求和. 思路 用\(tag\)记录这一块是否已全为\(1\). 除分块外,还可用 树状数组+并查集(链表) 或者 线 ...
- loj 数列分块入门 6 9(区间众数)
6 题意 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及单点插入,单点询问,数据随机生成. 题解 参考:http://hzwer.com/8053.html 每个块内用一个\(vecto ...
- LOJ 数列分块入门系列
目录 1.区间加+单点查 每个块维护tag,散的暴力改. code: #include<bits/stdc++.h> using namespace std; const int maxn ...
- LOJ6285 数列分块入门9(分块)
昨天对着代码看了一晚上 然后今天终于在loj上过了 数列分块入门9题撒花★,°:.☆( ̄▽ ̄)/$:.°★ . 然后相当玄学 块的大小调成\(\sqrt{n}\)会TLE,改成150就过了 啧 然后就 ...
- LOJ——#6277. 数列分块入门 1
~~推荐播客~~ 「分块」数列分块入门1 – 9 by hzwer 浅谈基础根号算法——分块 博主蒟蒻,有缘人可直接观摩以上大佬的博客... #6277. 数列分块入门 1 题目大意: 给出一个长为 ...
随机推荐
- VsCode C++ 语法检测失效不标红色波浪线 解决办法
如果enable Squiggles 无效,按照下图里配置设置解决问题. 如图:
- JS中call、apply、bind
call就是挨个传值,apply传一个数组,bind也是挨个传值 call() 和 apply() 会执行这个函数bind并不会而是将绑定好的this重新返回一个新函数
- ubuntu - 程序运行的一些基础知识
1.指定编码格式 -finput-charset=GB2312 指定 C 程序的编码方式为 GB2312,不指定时默认编码方式为 UTF-8 -fexec-charset=GB2312 指定 可执行程 ...
- windows下C#读文件遇到一个路径的天坑
在win下面准备了一个文件,右键属性然后"安全"复制完整的文件路径, 放到C#代码(vs中编写)中来读取,竟然死活异常: System.IO.IOException HResult ...
- 金蝶K3无法查看关联信息
场景: 某个用户点击采购订单界面--关联信息,界面显示正在加载,但是无法显示所有关联单据. 步骤: 1. 在其他电脑登录存在同样问题. 2. 其他模块可以正常显示 3. 删除该用户t_UserProf ...
- 可汗儿童版kids安卓版下载安装教程
可汗儿童版kids安卓版幼儿版下载安装教程 点击下面 http://vip.ho27.com/Khan.apk 备用下载链接 天翼网盘下载安装就行 https://cloud.189.cn/t/6RV ...
- dockerfile实践学习
一.dockerfile简介 镜像是分层存储的,每一层在前一层的基础上进行修改. 容器也是分层存储,已经向为基础层,在其他基础上加一层作为容器运行的存储层. 创建镜像的另种两种方法 手动修改容器内容, ...
- 接口拿到的id和传到后台的id不一致,导致查询详情和编辑报错
碰到这个问题真是百思不得其解.接口上打印的值和数据库一致,浏览器查看response的反馈也一致.但是一在页面打印请求回来的值,就变了,变成了另一个id,但是其他数据又和数据库一致. 查了一圈也没有查 ...
- redis过期事件监听
1 修改 redis.conf配置文件: K Keyspace events, published with keyspace@ prefix事件 E Keyevent events, publish ...
- xshell he xftp下载网址
https://www.xshell.com/zh/free-for-home-school/