P13977 数列分块入门 2 题解
Planetary_system · · 题解
题面解释:
分块维护区间加,区间查询排名。
思路分析:
思路与教主的魔法完全相同。
散块直接暴力。修改时直接加,查询时也是直接枚举。
对于整块暴力排序,二分查询。每次被当做散块修改后都进行排序,保证其单调性。查询的时候由于保证单调性直接二分查找即可。
AC Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,p,q,a[N],b[N],c[N];
bool cmp(int x,int y){
return x>y;
}
void resort(int id){
int l=id*q,r=min(l+q-1,n-1);
for(int i=l;i<=r;i++)c[i]=a[i];
sort(c+l,c+r+1,cmp);
}
int query(int id,int v){
int l=id*q,r=min(l+q-1,n-1);
v-=b[id];
if(c[l]<v)return 0;
int b=l,e=r;
while(b+1<e){
int mid=b+e>>1;
if(c[mid]>=v)b=mid;
else e=mid;
}
if(c[e]>=v)return e-l+1;
else if(c[b]>=v)return b-l+1;
else return 0;
}
signed main(){
scanf("%lld",&n);
q=(int)sqrt(n/log(n));
for(int i=0;i<n;i++)
scanf("%lld",&a[i]),c[i]=a[i];
for(int l=0,r;l<n;l+=q){
r=min(l+q-1,n-1);
sort(c+l,c+r+1,cmp);
}
for(int T=1;T<=n;T++){
int op,l,r,m;
scanf("%lld%lld%lld%lld",&op,&l,&r,&m);
l--;r--;
if(op==0){
int _l=l,_r=r;
for(;l%q&&l<=r;l++)a[l]+=m;
for(;l+q-1<=r;l+=q)b[l/q]+=m;
for(;l<=r;l++)a[l]+=m;
resort(_l/q);
if(_l/q!=_r/q)resort(_r/q);
}
else{
int ans=0;
for(;l%q&&l<=r;l++)if(a[l]+b[l/q]<m*m)ans++;
for(;l+q-1<=r;l+=q)ans+=q-query(l/q,m*m);
for(;l<=r;l++)if(a[l]+b[l/q]<m*m)ans++;
printf("%lld\n",ans);
}
}
return 0;
}