P13977 数列分块入门 2 题解
P13977 数列分块入门 2
设块号为
首先预处理出每个位置处于的块,记作
修改操作
对于
对于
对于
询问操作
对于
对于
对于
总时间复杂度
#include <bits/stdc++.h>
using namespace std;
struct node
{
long long val,p;
}nei[500][500];
long long n,k,op,l,r,c,a[200010],id[200010],add[200010],num[200010],d[200010];
bool cmp(struct node a,struct node b)
{
return a.val<b.val;
}
void adde()
{
long long p=id[l],q=id[r];
if(p==q)
{
for(long long i=l;i<=r;i++)
{
a[i]+=c;
nei[p][d[i]].val+=c;
}
sort(nei[p]+1,nei[p]+num[p]+1,cmp);
for(int j=1;j<=num[p];j++)d[nei[p][j].p]=j;
}
else
{
for(long long i=p+1;i<=q-1;i++)
add[i]+=c;
for(long long i=l;i<=p*k;i++)
{
a[i]+=c;
nei[p][d[i]].val+=c;
}
sort(nei[p]+1,nei[p]+num[p]+1,cmp);
for(int j=1;j<=num[p];j++)d[nei[p][j].p]=j;
for(long long i=(q-1)*k+1;i<=r;i++)
{
a[i]+=c;
nei[q][d[i]].val+=c;
}
sort(nei[q]+1,nei[q]+num[q]+1,cmp);
for(int j=1;j<=num[q];j++)d[nei[q][j].p]=j;
}
}
long long search(long long z,long long key)
{
long long l=0,r=num[z];
while(l<r)
{
long long mid=(l+r+1)/2;
if(nei[z][mid].val<key)l=mid;
else r=mid-1;
}
return l;
}
long long ask()
{
long long p=id[l],q=id[r],ans=0;
if(p==q)
{
for(long long i=l;i<=r;i++)if(a[i]+add[p]<c*c)ans++;
return ans;
}
else
{
for(long long i=p+1;i<=q-1;i++)ans+=search(i,c*c-add[i]);
for(long long i=l;i<=p*k;i++)if(a[i]+add[p]<c*c)ans++;
for(long long i=(q-1)*k+1;i<=r;i++)if(a[i]+add[q]<c*c)ans++;
return ans;
}
}
int main()
{
scanf("%lld",&n);
k=sqrt(n);
for(long long i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
id[i]=(i-1)/k+1;num[id[i]]++;
nei[id[i]][i-(id[i]-1)*k].val=a[i];
nei[id[i]][i-(id[i]-1)*k].p=i;
}
for(long long i=1;i<=id[n];i++)
{
sort(nei[i]+1,nei[i]+num[i]+1,cmp);
for(int j=1;j<=num[i];j++)d[nei[i][j].p]=j;
}
for(long long i=1;i<=n;i++)
{
scanf("%lld%lld%lld%lld",&op,&l,&r,&c);
if(op==0)adde();
else if(op==1)printf("%lld\n",ask());
}
return 0;
}