数列分块入门 4
链接:LibreOj6281
题目描述
给出一个长为n的数列,以及n个操作,操作涉及区间开方,区间求和。
输入格式
第一行输入一个数字n。
第二行输入n个数字,第i个数字为 a[i],以空格隔开。
接下来输入n行询问,每行输入四个数字op、l、r、c,以空格隔开。
若 op==0,将[l,r]之间的数字都开方(sqrt向下取整)
若 op==1,表示询问[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
分析:
开方比较难操作,对于区间和sum,如果区间每个值都开方,那么必须把所有值加一遍才能更新区间和。
但是一个不为0的数字多开方几次一定会变成1。遍历的时候判断如果是1或者0直接跳过因为1和0开方不变。
开一个数组mark标记区间是否全是0和1,在查询的时候判断区间全是0和1就可以直接跳过一个区间。
我的代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#include<sstream>
#include<memory>
#include<utility>
#include<functional>
#include<iterator>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=5e4+5;
int l[maxm],r[maxm];
int a[maxm],sum[maxm];
int belong[maxm];
int mark[maxm];
int block,num;
int n;
void build(){
block=sqrt(n);
num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
l[i]=(i-1)*block+1;
r[i]=i*block;
sum[i]=0;
mark[i]=0;//初始化mark
}
r[num]=n;
}
void pd(int x){
for(int i=l[x];i<=r[x];i++){
if(a[i]>1){
return ;
}
}
mark[x]=1;
}
void update(int x,int y){
if(belong[x]==belong[y]){
if(mark[belong[x]]){
return ;
}
for(int i=x;i<=y;i++){
if(a[i]<=1){
continue;
}
sum[belong[i]]-=a[i]-sqrt(a[i]);//维护区间和
a[i]=sqrt(a[i]);
}
pd(belong[x]);//每次操作判断能否mark区间
return ;
}
for(int i=x;i<=r[belong[x]];i++){
if(a[i]<=1)continue;
sum[belong[i]]-=a[i]-sqrt(a[i]);
a[i]=sqrt(a[i]);
}
pd(belong[x]);
for(int i=l[belong[y]];i<=y;i++){
if(a[i]<=1)continue;
sum[belong[i]]-=a[i]-sqrt(a[i]);
a[i]=sqrt(a[i]);
}
pd(belong[y]);
for(int i=belong[x]+1;i<belong[y];i++){
if(mark[i])continue;
for(int j=l[i];j<=r[i];j++){
if(a[j]<=1)continue;
sum[belong[j]]-=a[j]-sqrt(a[j]);
a[j]=sqrt(a[j]);
}
pd(i);
}
}
int ffind(int x,int y){
int ans=0;
if(belong[x]==belong[y]){
for(int i=x;i<=y;i++){
ans+=a[i];
}
return ans;
}
for(int i=x;i<=r[belong[x]];i++){
ans+=a[i];
}
for(int i=l[belong[y]];i<=y;i++){
ans+=a[i];
}
for(int i=belong[x]+1;i<belong[y];i++){
ans+=sum[i];
}
return ans;
}
int main(){
scanf("%d",&n);
build();
for(int i=1;i<=n;i++){
belong[i]=(i-1)/block+1;
scanf("%d",&a[i]);
sum[belong[i]]+=a[i];
}
for(int i=1;i<=n;i++){
int d,x,y,c;
scanf("%d%d%d%d",&d,&x,&y,&c);
if(d==0){
update(x,y);
}else{
printf("%d\n",ffind(x,y));
}
}
return 0;
}