#6281. 数列分块入门 5 - 题目 - LibreOJ (loj.ac)

区间开方,区间求和题。

显然,针对区间维护开方操作很难做到,于是考虑其值的性质,显然,int范围内的值最多开方6次就会变为1,之后再开方依然为1,于是考虑暴力维护一个区间内的值是否全部为1即可,全部为1标记上之后再遇到O(1)处理即可。复杂度大概就为O(n*6+n*sqrt(n))

代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(1e5)+5;
int a[maxn];
int sum[maxn];
int bel[maxn];
int L[maxn],R[maxn];
bool 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]=i*block;
for(int j=L[i];j<=R[i];j++){
bel[j]=i;
sum[i]+=a[j];
}
}
}
void update(int l,int r){
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(tag[bel[i]])break;
sum[bel[i]]=sum[bel[i]]-a[i]+int(sqrt(a[i]));
a[i]=int(sqrt(a[i]));
}
}
else{
for(int i=l;i<=R[bel[l]];i++){
if(tag[bel[i]])break;
sum[bel[i]]=sum[bel[i]]-a[i]+int(sqrt(a[i]));
a[i]=int(sqrt(a[i]));
}
for(int i=L[bel[r]];i<=r;i++){
if(tag[bel[i]])break;
sum[bel[i]]=sum[bel[i]]-a[i]+int(sqrt(a[i]));
a[i]=int(sqrt(a[i]));
}
for(int i=bel[l]+1;i<bel[r];i++){
bool fg=1;
for(int j=L[i];j<=R[i];j++){
if(tag[i])break;
sum[i]=sum[i]-a[j]+int(sqrt(a[j]));
a[j]=int(sqrt(a[j]));
if(a[j]>1)fg=0;
}
if(fg)tag[i]=1;
}
}
}
void calc(int l,int r){
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
ans+=a[i];
}
}
else{
for(int i=l;i<=R[bel[l]];i++){
ans+=a[i];
}
for(int i=L[bel[r]];i<=r;i++){
ans+=a[i];
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=sum[i];
}
}
cout<<ans<<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++){
int opt,l,r,c;
cin>>opt>>l>>r>>c;
if(opt){
calc(l,r);
}
else{
update(l,r);
}
}
return 0;
}

#6283. 数列分块入门 7 - 题目 - LibreOJ (loj.ac)

区间乘法,区间加法,单点询问

类似线段树的实现操作,注意先乘后加。当时我调bug花了很久,主要原因是在处理离散块的时候我直接对a数组进行了修改操作,导致标记数组出错,解决方法为直接对离散块所属的完整块进行下放标记的操作(暴力但是可行)

代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(1e5)+5;
const int modd=(1e4)+7;
int a[maxn];
int bel[maxn];
int L[maxn],R[maxn];
int tag1[maxn];
int tag2[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);
tag1[i]=0;
tag2[i]=1;
for(int j=L[i];j<=R[i];j++){
bel[j]=i;
}
}
}
void pushdown(int p){
int l=L[bel[p]],r=R[bel[p]];
for(int i=l;i<=r;i++){
a[i]=(a[i]*tag2[bel[p]]+tag1[bel[p]])%modd;
}
tag1[bel[p]]=0;
tag2[bel[p]]=1;
}
void add(int l,int r,int c){
if(bel[l]==bel[r]){
pushdown(l);
for(int i=l;i<=r;i++){
a[i]=(a[i]+c)%modd;
}
}
else{
pushdown(l);
for(int i=l;i<=R[bel[l]];i++){
a[i]=(a[i]+c)%modd;
}
pushdown(r);
for(int i=L[bel[r]];i<=r;i++){
a[i]=(a[i]+c)%modd;
}
for(int i=bel[l]+1;i<bel[r];i++){
tag1[i]=(tag1[i]+c)%modd;
}
}
}
void multiply(int l,int r,int c){
if(bel[l]==bel[r]){
pushdown(l);
for(int i=l;i<=r;i++){
a[i]=(a[i]*c)%modd;
}
}
else{
pushdown(l);
for(int i=l;i<=R[bel[l]];i++){
a[i]=(a[i]*c)%modd;
}
pushdown(r);
for(int i=L[bel[r]];i<=r;i++){
a[i]=(a[i]*c)%modd;
}
for(int i=bel[l]+1;i<bel[r];i++){
tag1[i]=(tag1[i]*c)%modd;
tag2[i]=(tag2[i]*c)%modd;
}
}
}
void calc(int i){
int ans=(a[i]*tag2[bel[i]]+tag1[bel[i]])%modd;
cout<<ans<<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++){
int opt,l,r,c;
cin>>opt>>l>>r>>c;
if(opt==0){
add(l,r,c);
}
if(opt==1){
multiply(l,r,c);
}
if(opt==2){
calc(r);
}
}
return 0;
}

#6284. 数列分块入门 8 - 题目 - LibreOJ (loj.ac)

区间询问等于一个数 c 的元素,并将这个区间的所有元素改为 c。

这题我折腾了挺久。思路为标记每个区间是否为同一个值,若是则标记为该值,否则标记为1e11。之后在分块的模板中再分三种情况进行分析。1.该区间全部为c,2.该区间全部为另外一个值,3.该区间的值不统一。注意点:在离散块情况2进行修改操作时需要先进行标记下放操作。

代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(1e5)+5;
ll a[maxn];
ll tag[maxn];
ll bel[maxn];
ll L[maxn],R[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);
tag[i]=1e11;
for(int j=L[i];j<=R[i];j++){
bel[j]=i;
}
}
}
void pushdown(int p){
for(int i=L[p];i<=R[p];i++){
a[i]=tag[p];
}
}
void ope(ll l,ll r,ll c){
ll ans=0;
if(bel[l]==bel[r]){
if(tag[bel[l]]==c){
ans+=r-l+1;
}
else if(tag[bel[l]]!=1e11){
pushdown(bel[l]);
for(int i=l;i<=r;i++){
a[i]=c;
}
tag[bel[l]]=1e11;
}
else{
for(int i=l;i<=r;i++){
if(a[i]==c)ans++;
else a[i]=c;
}
}
}
else{
if(tag[bel[l]]==c){
ans+=R[bel[l]]-l+1;
}
else if(tag[bel[l]]!=1e11){
pushdown(bel[l]);
for(int i=l;i<=R[bel[l]];i++){
a[i]=c;
}
tag[bel[l]]=1e11;
}
else{
for(int i=l;i<=R[bel[l]];i++){
if(a[i]==c)ans++;
else a[i]=c;
}
}
if(tag[bel[r]]==c){
ans+=r-L[bel[r]]+1;
}
else if(tag[bel[r]]!=1e11){
pushdown(bel[r]);
for(int i=L[bel[r]];i<=r;i++){
a[i]=c;
}
tag[bel[r]]=1e11;
}
else{
for(int i=L[bel[r]];i<=r;i++){
if(a[i]==c)ans++;
else a[i]=c;
}
}
for(int i=bel[l]+1;i<bel[r];i++){
if(tag[i]==c){
ans+=(R[i]-L[i]+1);
}
else if(tag[i]==1e11){
for(int j=L[i];j<=R[i];j++){
if(a[j]==c)ans++;
else a[j]=c;
}
tag[i]=c;
}
else{
tag[i]=c;
}
}
}
cout<<ans<<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 l,r,c;
cin>>l>>r>>c;
ope(l,r,c);
}
return 0;
}

LOJ数列分块入门九题(中)的更多相关文章

  1. LOJ 数列分块入门 9 题解题报告

    LOJ 数列分块入门 9 题解题报告 \(\text{By DaiRuiChen007}\) I. 数列分块入门 1 题目大意 \(\text{Link}\) 维护一个长度为 \(n\) 的序列,支持 ...

  2. 数列分块入门九题(三):LOJ6283~6285

    Preface 最后一题我一直觉得用莫队是最好的. 数列分块入门 7--区间乘法,区间加法,单点询问 还是很简单的吧,比起数列分块入门 7就多了个区间乘. 类似于线段树,由于乘法的优先级高于加法,因此 ...

  3. 数列分块入门九题(二):LOJ6280~6282

    Preface 个人感觉这中间的三题是最水的没有之一 数列分块入门 4--区间加法,区间求和 这个也是很多数据结构完爆的题目线段树入门题,但是练分块我们就要写吗 修改还是与之前类似,只不过我们要维护每 ...

  4. 数列分块入门九题(一):LOJ6277~6279

    Preface 分块,一个神奇的暴力算法.可以把很多\(O(n^2)\)的数据结构题的暴力优化到常数极小的\(O(n\sqrt n)\).当一些毒瘤题无法用线段树,主席树,平衡树,树状数组...... ...

  5. [Loj] 数列分块入门 1 - 9

    数列分块入门 1 https://loj.ac/problem/6277 区间加 + 单点查询 #include <iostream> #include <cstdio> #i ...

  6. loj 数列分块入门 6 9(区间众数)

    6 题意 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及单点插入,单点询问,数据随机生成. 题解 参考:http://hzwer.com/8053.html 每个块内用一个\(vecto ...

  7. loj 数列分块入门 5 7 8

    5 题意 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间开方,区间求和. 思路 用\(tag\)记录这一块是否已全为\(1\). 除分块外,还可用 树状数组+并查集(链表) 或者 线 ...

  8. LOJ 数列分块入门系列

    目录 1.区间加+单点查 每个块维护tag,散的暴力改. code: #include<bits/stdc++.h> using namespace std; const int maxn ...

  9. LOJ6285 数列分块入门9(分块)

    昨天对着代码看了一晚上 然后今天终于在loj上过了 数列分块入门9题撒花★,°:.☆( ̄▽ ̄)/$:.°★ . 然后相当玄学 块的大小调成\(\sqrt{n}\)会TLE,改成150就过了 啧 然后就 ...

  10. LOJ——#6277. 数列分块入门 1

    ~~推荐播客~~ 「分块」数列分块入门1 – 9 by hzwer 浅谈基础根号算法——分块 博主蒟蒻,有缘人可直接观摩以上大佬的博客... #6277. 数列分块入门 1 题目大意: 给出一个长为 ...

随机推荐

  1. how to make the windows console works with utf-8 encoded project

    the console of the windows os is not working in the utf-8 encoding, by default. When you force your ...

  2. LeetCode习题集

    作为一名本科计算机科学与技术的学生,<数据结构与算法><算法分析与设计>这两门课没有学到特别好 上了研究生之后感觉,这些东西需要重新拾起 于是,我找了一个平台,LeetCode ...

  3. Modern C++ ——constexpr的各种用法

    Modern C++ --constexpr的用法 Reference <现代C++语言核心特性解析> 为什么引入constexpr const可以定义常量,但也可以用来定义只读变量.co ...

  4. VM安装linux2022、设置root密码、设置国内更新源

    一.创建虚拟机 1.打开VM软件选择"创建新的虚拟机" 2.选择"典型"即可 3.选择"稍后安装操作系统" 4.选择客户机操作系统为&quo ...

  5. flannel提供的3种后端实现

    UDP(flanneld封装和解封装UDP) 实现原理 缺点(性能最差) UDP模式,封装和解封装的对象是三层IP包,提供三层的Overlay网络,是Flannel最早支持的一种方式,也是性能最差的一 ...

  6. linux中大括号、小括号、中括号的区别和用法

    大括号 {  } 1.用于取多个变量 可以进行取变量和字符串拼接,假设:var='1234'       echo  ${var}abcd    输出为:1234abcd 2.正则表达式,用于大括号内 ...

  7. 用字典代替'if-elif-else'

    在实际应用中,我们经常会需要采用if-elif-else控制语句以根据不同条件,作出不同的操作.if-elif-else固然可以,但是它也存在冗余的缺点,特别是当条件较多时这一缺点尤为明显.因此,本文 ...

  8. 【小记】copy 与 copy_backward

    copy 与 copy_backward copy 从前往后复制,result 参数指向目标容器的 begin 位置 copy*backward 从后往前复制,··· end 位置 Possible ...

  9. HarmonyOS基础

    目录 自适应布局 自适应拉伸布局 自适应缩放 自适应延伸 组件多态 ArkUI开发框架 基础组件 Text组件和Span组件 参考 参考:harmonyos3: 鸿蒙ArkUI eTS教程配套源码 参 ...

  10. R7-3 汉诺(Hanoi)塔问题

    R7-3 汉诺(Hanoi)塔问题 分数 20 全屏浏览题目 切换布局 作者 张高燕 单位 浙大城市学院 古代某寺庙中有一个梵塔,塔内有3个座A.B和C,座A上放着64个大小不等的盘,其中大盘在下,小 ...