题目描述
给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,询问区间内小于某个值 xxx 的元素个数。
输入格式
第一行输入一个数字 nnn。
第二行输入 nnn 个数字,第 i 个数字为 aia_iai,以空格隔开。
接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt、lll、rrr、ccc,以空格隔开。
若 opt=0\mathrm{opt} = 0opt=0,表示将位于 [l,r][l, r][l,r] 的之间的数字都加 ccc。
若 opt=1\mathrm{opt} = 1opt=1,表示询问 [l,r][l, r][l,r] 中,小于 c2c^2c2 的数字的个数。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2
样例输出
3
0
2
数据范围与提示
对于 100% 100\%100% 的数据,1≤n≤50000,−231≤others 1 \leq n \leq 50000, -2^{31} \leq \mathrm{others}1≤n≤50000,−231≤others、ans≤231−1 \mathrm{ans} \leq 2^{31}-1ans≤231−1。
题解:妈的什么情况,老子足足WA了9发才终于改好。气死
对于每次区间操作:
1.不完整的块 的O(√n)个元素怎么处理?
2.O(√n)个 整块 怎么处理?
3.要预处理什么信息(复杂度不能超过后面的操作)?
我们先来思考只有询问操作的情况,不完整的块枚举统计即可;而要在每个整块内寻找小于一个值的元素数,于是我们不得不要求块内元素是有序的,这样就能使用二分法对块内查询,需要预处理时每块做一遍排序,复杂度O(nlogn),每次查询在√n个块内二分,以及暴力2√n个元素,总复杂度O(nlogn + n√nlog√n)。
可以通过均值不等式计算出更优的分块大小,就不展开讨论了
那么区间加怎么办呢?
套用第一题的方法,维护一个加法标记,略有区别的地方在于,不完整的块修改后可能会使得该块内数字乱序,所以头尾两个不完整块需要重新排序,复杂度分析略。
在加法标记下的询问操作,块外还是暴力,查询小于(x – 加法标记)的元素个数,块内用(x – 加法标记)作为二分的值即可。
分块真的是什么鬼东西、、、
代码:
#include<bits/stdc++.h>
using namespace std;
struct aaa{
long long w;
int v;
}aa[100001];
int n,m,i,j,l,r,t1,ll,rr,mid,ans,t;
long long a[100001],f[100001],b[100001],c;
bool cmp(aaa a,aaa b){
return a.w<b.w;
}
int main(){
scanf("%d",&n);
m=sqrt(n);
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
aa[i].w=a[i];aa[i].v=i;
b[i]=(i-1)/m+1;
}
for(i=1;i<m;i++){
sort(aa+(i-1)*m+1,aa+i*m+1,cmp);
}
sort(aa+(m-1)*m+1,aa+n+1,cmp);
for(i=1;i<=n;i++){
scanf("%d%d%d%lld",&t1,&l,&r,&c);
if(t1==0){
if(b[l]==b[r]){
for(j=(b[l]-1)*m+1;j<l;j++)aa[j].w=a[j];
for(j=r+1;j<=b[l]*m;j++)aa[j].w=a[j];
for(j=l;j<=r;j++){
a[j]+=c;
aa[j].w=a[j];
}
sort(aa+(b[l]-1)*m+1,aa+b[l]*m+1,cmp);
}
else{
for(j=(b[l]-1)*m+1;j<l;j++){
aa[j].w=a[j];
aa[j].v=j;
}
for(j=r+1;j<=b[r]*m;j++){
aa[j].w=a[j];
aa[j].v=j;
}
for(j=l;j<=b[l]*m;j++){
a[j]+=c;
aa[j].w=a[j];
aa[j].v=j;
}
for(j=(b[r]-1)*m+1;j<=r;j++){
a[j]+=c;
aa[j].w=a[j];
aa[j].v=j;
}
sort(aa+(b[l]-1)*m+1,aa+b[l]*m+1,cmp);
sort(aa+(b[r]-1)*m+1,aa+b[r]*m+1,cmp);
for(j=b[l]+1;j<b[r];j++)f[j]+=c;
}
}
else{
c*=c;ans=0;
if(b[l]==b[r]){
for(j=l;j<=r;j++)if(f[b[l]]+a[j]<c)ans++;
}
else{
for(j=l;j<=b[l]*m;j++)
if(f[b[l]]+a[j]<c)ans++;
for(j=(b[r]-1)*m+1;j<=r;j++)
if(f[b[r]]+a[j]<c)ans++;
for(j=b[l]+1;j<b[r];j++){
ll=(j-1)*m+1;rr=j*m;
t=ll-1;
while(ll<=rr){
mid=(ll+rr)/2;
if(aa[mid].w+f[j]<c){
t=max(t,mid);
ll=mid+1;
}
else rr=mid-1;
}
ans+=t-(j-1)*m;
}
}
printf("%d\n",ans);
}
}
}