LOJ6279数列分块3。。

在这里插入图片描述

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值