LOJ-6279-数列分块入门3(分块, 二分)

链接:

https://loj.ac/problem/6279

题意:

给出一个长为 的数列,以及 个操作,操作涉及区间加法,询问区间内小于某个值 的前驱(比其小的最大元素)。

思路:

同样的分块加二分,只不过是更新值

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
//#include <memory.h>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <stack>
#include <string>
#include <assert.h>
#include <iomanip>
#define MINF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;

int a[MAXN];
int Rank[MAXN], Tag[MAXN];
vector<int> Vec[MAXN];
int part, n;

void Re(int pos)
{
    Vec[pos].clear();
    for (int i = (pos-1)*part+1;i <= pos*part;i++)
        Vec[pos].push_back(a[i]);
    sort(Vec[pos].begin(), Vec[pos].end());
}

void Update(int l, int r, int c)
{
    for (int i = l;i <= min(Rank[l]*part, r);i++)
        a[i] += c;
    Re(Rank[l]);
    if (Rank[l] != Rank[r])
    {
        for (int i = max(l, (Rank[r]-1)*part+1);i <= r;i++)
            a[i] += c;
        Re(Rank[r]);
    }
    for (int i = Rank[l]+1;i <= Rank[r]-1;i++)
    {
        Tag[i] += c;
    }
}

int Query(int l, int r, int c)
{
    int res = -1;
    for (int i = l;i <= min(Rank[l]*part, r);i++)
    {
        if (a[i]+Tag[Rank[l]] < c)
            res = max(res, a[i]+Tag[Rank[l]]);
    }
    if (Rank[l] != Rank[r])
    {
        for (int i = max((Rank[r]-1)*part+1, l);i <= r;i++)
        {
            if (a[i]+Tag[Rank[r]] < c)
                res = max(res, a[i]+Tag[Rank[r]]);
        }
    }
    for (int i = Rank[l]+1;i <= Rank[r]-1;i++)
    {
        int pos = lower_bound(Vec[i].begin(), Vec[i].end(), c-Tag[i])-Vec[i].begin();
        if (pos >= 1)
            res = max(res, Vec[i][pos-1]+Tag[i]);
    }
    return res;
}

int main()
{

    scanf("%d", &n);
    part = sqrt(n);
    for (int i = 1;i <= n;i++)
        scanf("%d", &a[i]);
    for (int i = 1;i <= n;i++)
    {
        Rank[i] = (i-1)/part+1;
        Vec[Rank[i]].push_back(a[i]);
    }
    for (int i = 1;i <= Rank[n];i++)
        sort(Vec[i].begin(), Vec[i].end());
    int op, l, r, c;
    for (int i = 1;i <= n;i++)
    {
        scanf("%d %d %d %d", &op, &l, &r, &c);
        if (op == 0)
            Update(l, r, c);
        else
            printf("%d
", Query(l, r, c));
    }

    return 0;
}
原文地址:https://www.cnblogs.com/YDDDD/p/11397561.html