#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5+7;
int belong[maxn],l[maxn],r[maxn];
int n,num,block;
int a[maxn],sum[maxn];
set<int>s[2005];
ll read()
{
char ch=getchar();long long ret=0,f=1;
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
return f*ret;
}
void build()
{
block = sqrt(n);//块的大小
num = n / block; if(n % block) num++; //块的多少
for(int i = 1; i <= num; i++)
l[i] = (i - 1) * block + 1, r[i] = i * block;
r[num] = n;//最后一块特判 有一个数据都算一块
for(int i = 1; i <= n; i++)
{
belong[i] = (i - 1) / block + 1;
s[belong[i]].insert(a[i]); //将数据放入块中
}
}
void update(int x,int y,int c)//修改块的数据
{
int t1 = belong[x], t2 = belong[y];
for(int i = x; i <= min(r[t1], y); i++) //前面一块
{
s[t1].erase(a[i]);//删除此数据
a[i] += c;//修改-
s[t1].insert(a[i]);//添加数据
}
if(t1 != t2) for(int i = l[t2]; i <= y; i++) //后面一块
{
s[t2].erase(a[i]);
a[i]+=c;
s[t2].insert(a[i]);
}
for(int i = t1 + 1; i < t2; i++)//中间一块
sum[i] += c; //sum = 懒人标记
}
int query(int x,int y,int c)
{
int ans = -1;
int t1 = belong[x], t2 = belong[y];
//注意sum是加法标记
for(int i = x; i <= min(r[t1], y); i++)
if(a[i] + sum[t1] < c) ans = max(ans,a[i]+sum[t1]);
//前端查找
if(t1 != t2) for(int i = l[t2]; i <= y; i++)
if(a[i] + sum[t2] < c) ans = max(ans,a[i]+sum[t2]);
//后端查找
for(int i = t1 + 1; i < t2; i++)
{
int x = c - sum[i];
set<int>::iterator it = s[i].lower_bound(x);
if(it == s[i].begin()) continue;
it--;
ans = max(ans,*it+sum[i]);
}//中段查找
return ans;
}
int main()
{
n = read();
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
build();
for(int i = 1; i <= n; i++)
{
int op = read(), l = read(), r = read(), c = read();
if(op == 1) printf("%d\n",query(l,r,c));
else update(l,r,c);
}
return 0;
}
LOJ6279数列分块3。。
最新推荐文章于 2022-09-17 17:18:18 发布