Loading

LibreOJ - 6279 数列分块入门 3(块内二分)

题目描述

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

第一行输入一个数字 。

第二行输入n个数字,第i个数字为ai,以空格隔开。

接下来输入n行询问,每行输入四个数字opt,l,r,c,以空格隔开。

若opt=0,表示将位于l,r的之间的数字都加c。

若opt=1,表示询问l,r中,c的前驱的值(不存在则输出 )。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4

样例输出

3
-1

 

和上一题类似,只不过是求区间条件最值。注意!上一题一通lower_bound操作最后得到的是偏移量,而上一题是求的元素个数,所以直接累加答案即可。而这个题得到的是数在b数组的位置而非a数组,ppos是b数组的索引!没注意到这点被坑惨了T^T

 

#include <bits/stdc++.h>
using namespace std;
int a[500005], b[500005], add[500005];  
int L[500005], R[500005];
int pos[500005];
int n, t;
inline int read(){   int s=0,w=1;   char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();   return s*w;}
void change(int l, int r, int d) {
    int p = pos[l], q = pos[r];
    if (p == q) {
        for (int i = l; i <= r; i++) a[i] += d;
        for (int i = L[p]; i <= R[p]; i++) 
        {
            a[i] += add[p];
            b[i] = a[i];
        }
        add[p] = 0;
        sort(b + L[p], b + R[p] + 1);
    } else {
        for (int i = p + 1; i <= q - 1; i++) add[i] += d;
        for (int i = l; i <= R[p]; i++) a[i] += d;
        for (int i = L[p]; i <= R[p]; i++) 
        {
            a[i] += add[p];
            b[i] = a[i];
        }
        add[p] = 0;
        sort(b + L[p], b + R[p] + 1);
        for (int i = L[q]; i <= r; i++) a[i] += d;
        for (int i = L[q]; i <= R[q]; i++) 
        {
            a[i] += add[q];
            b[i] = a[i];
        }
        add[q] = 0;
        sort(b + L[q], b + R[q] + 1);
    }
}
int ask(int l, int r, int c) {
    int p = pos[l], q = pos[r], ans = -1;
    if (p == q) {
        for (int i = l; i <= r; i++)
            if (a[i] + add[p] < c)
                ans = max(ans, a[i] + add[p]);
        return ans;
    } else {
        for (int i = p + 1; i <= q - 1; i++) {
            int ppos = lower_bound(b + L[i], b + R[i] + 1, c - add[i]) - b;//查找小于c的最大数 注意是b[ppos-1]而非a[ppos-1]! 
            if(ppos > L[i]) ans = max(ans, b[ppos - 1] + add[i]);
        }
        for (int i = l; i <= R[p]; i++)
            if (a[i] + add[p] < c) ans = max(ans, a[i] + add[p]);
        for (int i = L[q]; i <= r; i++)
            if (a[i] + add[q] < c) ans = max(ans, a[i] + add[q]);
        return ans;
    }
}
int main() {
    cin >> n;
    memset(add, 0, sizeof(add));
    for (int i = 1; i <= n; i++) {
        a[i] = read();
        b[i] = a[i];
    }
    t = sqrt(n);
    for (int i = 1; i <= t; i++) {
        L[i] = (i - 1) * sqrt(n) + 1;
        R[i] = i * sqrt(n);
    }
    if (R[t] < n)
        t++, L[t] = R[t - 1] + 1, R[t] = n;
    for (int i = 1; i <= t; i++)
    {
        for (int j = L[i]; j <= R[i]; j++) {
            pos[j] = i;
        }
        sort(b + L[i], b + R[i] + 1);
    }
    for (int i = 1; i <= n; i++) {
        int opt, l, r, c;
        opt = read(), l = read(), r = read(), c = read();
        if (opt == 0) {
            change(l, r, c);
        } else {
            cout << ask(l, r, c) << endl;
        }
    }
}

 

posted @ 2020-07-14 20:24  脂环  阅读(207)  评论(0编辑  收藏  举报