码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-07-22 11:22:40      阅读:54      评论:0      收藏:0      [点我收藏+]

标签:++i   info   str   problem   return   题目   can   operator   bool   

题目链接

解题思路

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

代码

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\n",find(l,r,c*c));
    }
    return 0;                                                                 
}

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

标签:++i   info   str   problem   return   题目   can   operator   bool   

原文地址:https://www.cnblogs.com/shuitiangong/p/13359014.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!