LibreOJ 6278 数列分块入门 2(分块区间加法,二分)

Posted shuitiangong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LibreOJ 6278 数列分块入门 2(分块区间加法,二分)相关的知识,希望对你有一定的参考价值。

题目链接

解题思路

??询问区间小于某个数个个数显然可以用二分来做,但是如果配合上区间加法就有些复杂了。即使对每个区间排序,用标记来代替修改,但是对于边缘的数据来说,需要暴力修改,而暴力修改后打破区间的有序性。那就暴力修改之后再重新排序(没错,就是这么狠(笑

代码

const int maxn = 1e5+10;
struct INFO {
    int num, i;
    INFO(int a=0, int b=0): num(a), i(b) {}
    bool operator < (const INFO &a) const {
        return num < a.num;
    }
} arr[maxn];
int n,sz,num,l[maxn],r[maxn],bl[maxn],lazy[maxn];
void build() {
    num = (n+sz-1)/sz;
    for (int i = 1; i<=num; ++i) {
        l[i] = (i-1)*sz+1, r[i] = i*sz;
    }
    r[num] = n;
    for (int i = 1; i<=n; ++i) bl[i] = (i-1)/sz+1;
    for (int i = 1; i<=num; ++i) sort(arr+l[i],arr+r[i]+1); 
}
void update(int a, int b, int c) {
    if (bl[a]==bl[b]) {
        for (int i = l[bl[a]]; i<=r[bl[a]]; ++i)    
            if (arr[i].i>=a && arr[i].i<=b) arr[i].num += c;
        sort(arr+l[bl[a]], arr+r[bl[a]]+1);
        return;
    }
    for (int i = bl[a]+1; i<bl[b]; ++i) lazy[i] += c;
    for (int i = l[bl[a]]; i<=r[bl[a]]; ++i) 
        if (arr[i].i>=a) arr[i].num += c;
    for (int i = l[bl[b]]; i<=r[bl[b]]; ++i) 
        if (arr[i].i<=b) arr[i].num += c;
    sort(arr+l[bl[a]], arr+r[bl[a]]+1);
    sort(arr+l[bl[b]], arr+r[bl[b]]+1);
}
int find(int a, int b, int c) {
    int ans = 0;
    if (bl[a]==bl[b]) {
        for (int i = l[bl[a]]; i<=r[bl[a]]; ++i) 
            if (arr[i].i>=a && arr[i].i<=b && arr[i].num+lazy[bl[i]]<c) ++ans;
        return ans;
    }
    for (int i = bl[a]+1; i<bl[b]; ++i)  
        ans += lower_bound(arr+l[i],arr+r[i]+1,INFO(c-lazy[i],0))-arr-l[i];
    for (int i = l[bl[a]]; i<=r[bl[a]]; ++i) 
        if (arr[i].i>=a && arr[i].num+lazy[bl[i]]<c) ++ans;
    for (int i = l[bl[b]]; i<=r[bl[b]]; ++i) 
        if (arr[i].i<=b && arr[i].num+lazy[bl[i]]<c) ++ans;
    return ans;
}
int main() {
    scanf("%d",&n);
    for (int i = 1; i<=n; ++i) {
        scanf("%d",&arr[i].num);
        arr[i].i = i;
    }
    sz = sqrt(n); build();
    for (int i = 1,op,l,r,c; i<=n; ++i) {
        scanf("%d%d%d%d",&op,&l,&r,&c);
        if (!op) update(l,r,c);
        else printf("%d
",find(l,r,c*c));
    }
    return 0;                                                                 
}

以上是关于LibreOJ 6278 数列分块入门 2(分块区间加法,二分)的主要内容,如果未能解决你的问题,请参考以下文章

LiberOJ 6278 数列分块入门 2(分块)

loj 6278 6279 数列分块入门 2 3

#6278. 数列分块入门 2

LOJ#6278. 数列分块入门 2

数列分块入门1-9 LibreOJ

LibreOJ 6282. 数列分块入门 6