P13978 数列分块入门 3 题解
思路
序列分块板子。同时维护每块的原序列和排序后的样子。
修改的话,散块暴力修改再排序,整块打懒惰标记。
查询的话,散块暴力查询,整块二分。
复杂度
实现
可以逐块处理。
#include<stdio.h>
#include<algorithm>
#define N 200009
#define B 8
using namespace std;
inline char nc()
{
static char*l,*r,buf[99999];
return l==r&&(r=(l=buf)+fread(buf,1,99999,stdin),l==r)?EOF:*l++;
}
inline void read(int&x)
{
bool t=0;char c=nc();for(;c<'0'||'9'<c;t|=c=='-',c=nc());
for(x=0;'0'<=c&&c<='9';x=(x<<3)+(x<<1)+(c^48),c=nc());if(t)x=-x;
}
int n,a[N],o[N],l[N],r[N],x[N],b[1<<B],c[1<<B];long long lazy,ans[N];
main()
{
read(n);for(int i=0;i<n;read(a[i++]));
for(int i=0;i<n;read(o[i]),read(l[i]),read(r[i]),read(x[i]),--l[i],--r[i],
ans[i++]=-(1ll<<60));
for(int i=0;i<n;i+=1<<B)
{
int len=1<<B;if(i>>B==n>>B)len=n-i;
for(int j=0;j<len;++j)b[j]=c[j]=a[j|i];
sort(c,c+len);lazy=0;
for(int j=0;j<n;++j)if(o[j])
{
if(r[j]<i)continue;
if(i+len-1<l[j])continue;
if(l[j]<=i&&i+len-1<=r[j])
{
long long y=x[j]-lazy;
if(y<=c[0])continue;
if(c[len-1]<y)ans[j]=max(ans[j],c[len-1]+lazy);
else ans[j]=max(ans[j],*(lower_bound(c,c+len,y)-1)+lazy);
}
else for(int k=max(0,l[j]-i);k<=min(len-1,r[j]-i);++k)
if(b[k]+lazy<x[j])ans[j]=max(ans[j],b[k]+lazy);
}
else
{
if(r[j]<i)continue;
if(i+len-1<l[j])continue;
if(l[j]<=i&&i+len-1<=r[j])lazy+=x[j];
else
{
for(int k=0;k<len;c[k]=b[k],++k)
{
b[k]+=lazy;
if(l[j]<=(i|k))if((i|k)<=r[j])b[k]+=x[j];
}
sort(c,c+len);lazy=0;
}
}
}
for(int i=0;i<n;++i)if(o[i])printf("%lld\n",ans[i]==-(1ll<<60)?-1:ans[i]);
}