给出一个长为 nn 的数列 a1…ana1…an,以及 nn 个操作,操作涉及区间开方,区间求和。
Input
第一行输入一个数字 n(1≤n≤50000)n(1≤n≤50000)。
第二行输入 nn 个非负整数,第ii个数字为 ai,(0≤ai≤109)ai,(0≤ai≤109),以空格隔开。
接下来输入 nn 行询问,每行输入四个数字 opt,l,r,copt,l,r,c,以空格隔开。
若 opt=0opt=0,表示将位于[l,r][l,r] 的之间的数字都开方。对于区间中每个 ai(l≤i≤r),ai→⌊√ai⌋ai(l≤i≤r),ai→⌊√ai⌋
若 opt=1opt=1,表示询问位于[l,r][l,r] 的所有数字的和。
Output
对于每次询问,输出一z行一个数字表示答案。
保证所有数据在int
范围内
Sample Input
4 1 2 2 3 0 1 3 1 1 1 4 4 0 1 2 2 1 1 2 4
Sample Output
6 2
题目链接 一道普通题
首先明确一个数,开方7次就是1了,对于一个区间全部是1的,可以直接标记,在开方操作的时候跳过去;
对于没有标记的区间,暴力开方;
分块的一般思路:
1,处理,l到R[ belong[ l ] ];
2,如果l,r不在同一块,则再处理L[ belong[ r ] ]到 r;
3,处理整块;
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=500005;
int belong[maxn];//一个数在哪一块里面
int block;//块的大小
int num;//表示一共有多少块
int l[maxn];//第i块的左边界
int r[maxn];//第i块的右边界
int a[maxn];
long long sum[maxn];
int tag[maxn];//标记值是否0或者1
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;
}
r[num]=n;//最后一块的右边界一定是n
for(int i=1;i<=n;i++)
belong[i]=(i-1)/block+1;//block属于第i块
for(int i=1;i<=n;i++)
sum[belong[i]]+=a[i];
memset(tag,0,sizeof tag);
}
void updata(int ll,int rr,int c)
{
int start=belong[ll];//找到l,r对应的块
int over=belong[rr];
for(int i=ll;i<=min(r[start],rr);i++)
{
sum[start]-=a[i];
a[i]=sqrt(a[i]);
sum[start]+=a[i];
}
if(start!=over)
{
for(int i=l[over];i<=rr;i++)
{
sum[over]-=a[i];
a[i]=sqrt(a[i]);
sum[over]+=a[i];
}
}
for(int i=start+1;i<=over-1;i++)
{
if(tag[i]==1) continue;
tag[i]=1;
sum[i]=0;
for(int j=l[i];j<=r[i];j++)
{
a[j]=sqrt(a[j]);
sum[i]+=a[j];
if(a[j]>1) tag[i]=0;
}
}
}
long long query(int ll,int rr)
{
int start=belong[ll];
int over=belong[rr];
long long ans=0;
for(int i=ll;i<=min(r[start],rr);i++)
ans+=a[i];
if(start!=over)
{
for(int i=l[over];i<=rr;i++)
ans+=a[i];
}
for(int i=start+1;i<over;i++)
{
ans+=sum[i];
}
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
build();
for(int i=1;i<=n;i++)
{
int o,ll,rr,c;
scanf("%d%d%d%d",&o,&ll,&rr,&c);
if(o==0)
{
updata(ll,rr,c);
}
else cout<<query(ll,rr)<<endl;
}
}
return 0;
}