P13978 数列分块入门 3 题解
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];
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);
}
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 LLONG_MIN;
int L=l,R=r,res;
while(L<=R){
int mid=L+R>>1;
if(c[mid]<v)L=mid+1,res=mid;
else R=mid-1;
}
return c[res]+b[id];
}
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);
}
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=LLONG_MIN;
for(;l%q&&l<=r;l++)if(a[l]+b[l/q]<m)ans=max(ans,a[l]+b[l/q]);
for(;l+q-1<=r;l+=q)ans=max(ans,query(l/q,m));
for(;l<=r;l++)if(a[l]+b[l/q]<m)ans=max(ans,a[l]+b[l/q]);
if(ans==LLONG_MIN)ans=-1;
printf("%lld\n",ans);
}
}
return 0;
}