#6281. 数列分块入门 5
Posted caijiaming
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#6281. 数列分块入门 5相关的知识,希望对你有一定的参考价值。
题目链接:https://loj.ac/problem/6281
题目描述
给出一个长为 nn 的数列 a_1ldots a_na1?…an?,以及 nn 个操作,操作涉及区间开方,区间求和。
输入格式
第一行输入一个数字 nn。
第二行输入 nn 个数字,第 ii 个数字为 a_iai?,以空格隔开。
接下来输入 nn 行询问,每行输入四个数字 mathrm{opt}, l, r, copt,l,r,c,以空格隔开。
若 mathrm{opt} = 0opt=0,表示将位于 [l, r][l,r] 的之间的数字都开方。对于区间中每个 a_i(lle ile r),: a_i ← leftlfloor sqrt{a_i} ight floorai?(l≤i≤r),ai?←?ai?
若 mathrm{opt} = 1opt=1,表示询问位于 [l, r][l,r] 的所有数字的和。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4
样例输出
6
2
数据范围与提示
对于 100\%100% 的数据,1 leq n leq 50000, -2^{31} leq mathrm{others}1≤n≤50000,?231≤others、mathrm{ans} leq 2^{31}-1ans≤231?1。
思路:这题棘手的地方在与块中开方的处理,怎么处理呢? 一个区间里每一个数的开方,这个要想不遍历一遍很难,但是遍历的话还要分块干嘛呢? 问题就在开方这个字眼,题目中给的范围里的数,
假设最大 2^32 最多开方6次就变为0或者1了 一个数变为0或者1 他再开方就不会再变化了,试想一下,假如一个区间里所有的数都变为了0或者1 那么还要处理吗 显然是不用的,所以我们就记录哪些区间
里的所有的数都变为了0或者1 是的话就不用处理这个块了,这就是分块在这里的巧妙之处了!!! 下面看代码:
#include<iostream> #include<string.h> #include<math.h> using namespace std; const int maxn=50000+5; int a[maxn]; int block; int bl[maxn]; int sum[maxn]; int flag[maxn]; void Updata_bl(int x) { if(flag[x]) return ; flag[x]=1; sum[x]=0; for(int i=(x-1)*block+1;i<=x*block;i++) { a[i]=sqrt(a[i]); sum[x]+=a[i]; if(a[i]>1) flag[x]=0; } } void Updata(int l,int r) { for(int i=l;i<=min(bl[l]*block,r);i++) { sum[bl[i]]-=a[i]; a[i]=sqrt(a[i]); sum[bl[i]]+=a[i]; } if(bl[l]!=bl[r]) { for(int i=(bl[r]-1)*block+1;i<=r;i++) { sum[bl[r]]-=a[i]; a[i]=sqrt(a[i]); sum[bl[r]]+=a[i]; } } for(int i=bl[l]+1;i<=bl[r]-1;i++) { Updata_bl(i); } } void Query(int l,int r) { int ans=0; for(int i=l;i<=min(bl[l]*block,r);i++) ans+=a[i]; if(bl[l]!=bl[r]) { for(int i=(bl[r]-1)*block+1;i<=r;i++) ans+=a[i]; } for(int i=bl[l]+1;i<=bl[r]-1;i++) ans+=sum[i]; cout<<ans<<endl; } int main() { int n; int opt,l,r,c; cin>>n ; memset(sum,0,sizeof(sum)); memset(flag,0,sizeof(flag)); block=sqrt(n); for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { bl[i]=(i-1)/block+1; sum[bl[i]]+=a[i]; } for(int i=1;i<=n;i++) { cin>>opt>>l>>r>>c; if(opt==0) Updata(l,r); else Query(l,r); } }
以上是关于#6281. 数列分块入门 5的主要内容,如果未能解决你的问题,请参考以下文章