P2801 教主的魔法

算是分块第一题了吧,抄题解过的。

简化版的题意:给你n个数的序列,支持区间加的修改,同时支持查询区间内大于等于w的数字的多少。

分块题的基本标志就是:xjb查询,普通修改。(来自qsc大佬的一句话)

显然如果用线段树的话维护这个东西就要吐血了。

我们使用分块,把一个序列分成\(\lceil \sqrt{n} \rceil\)块,每一块的长度最多为\(\lfloor \sqrt{n} \rfloor\)

考虑区间加,我们给一个块加一个lazy,如果是完整的块就直接用lazy加上去,否则就直接暴力修改。复杂度还是\(O(\sqrt{n})\)

如何查询区间内大于等于w的数字多少?可以用二分。

我们可以对同一个块内的元素排序,成为有序的序列就可以二分了。

注意:代码中有a数组、b数组和分块系列数组。其中a数组表示原顺序的序列,b数组表示分段排序后的序列。

具体看代码,做一道题我也不能总结出多少。

代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
const int maxn = 1000005;
int a[maxn], b[maxn], belong[maxn];
int ll[maxn], rr[maxn], lazy[maxn];
int len, num;
int n, m;
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar();
    return s * ans;
}
void init()
{
    len = sqrt(n);
    for(int i = 1; i <= n; i++) belong[i] = (i - 1) / len + 1;
    num = n / len; if(n % len) num++;
    for(int i = 1; i <= num; i++)
    {
        ll[i] = (i - 1) * len + 1; rr[i] = i * len;
    }
    rr[num] = n;
    for(int i = 1; i <= num; i++) std::sort(b + ll[i], b + rr[i] + 1);
}
void reset(int x)
{
    for(int i = ll[belong[x]]; i <= rr[belong[x]]; i++) b[i] = a[i];
    std::sort(b + ll[belong[x]], b + rr[belong[x]] + 1);
}
void update(int l, int r, int w)
{
    if(belong[l] == belong[r])
    {
        for(int i = l; i <= r; i++) a[i] += w;
        reset(l);
        return;
    }
    for(int i = l; i <= rr[belong[l]]; i++) a[i] += w;
    for(int i = ll[belong[r]]; i <= r; i++) a[i] += w; 
    for(int i = belong[l] + 1; i < belong[r]; i++) lazy[i] += w;
    reset(l); reset(r);
}
int query(int l, int r, int w)
{
    int ans = 0;
    if(belong[l] == belong[r])
    {
        for(int i = l; i <= r; i++) if(a[i] + lazy[belong[l]] >= w) ans++;
        return ans;
    }
    for(int i = l; i <= rr[belong[l]]; i++) if(a[i] + lazy[belong[l]] >= w) ans++;
    for(int i = ll[belong[r]]; i <= r; i++) if(a[i] + lazy[belong[r]] >= w) ans++;
    for(int i = belong[l] + 1; i < belong[r]; i++) ans += rr[i] - (std::lower_bound(b + ll[i], b + rr[i] + 1, w - lazy[i]) - b) + 1;
    return ans;
}
int main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; i++) b[i] = a[i] = read();
    init();
    char opt[3]; int l, r, w;
    while(m--)
    {
        scanf("%s", opt), l = read(), r = read(), w = read();
        if(opt[0] == 'M') update(l, r, w);
        else if(opt[0] == 'A') printf("%d\n", query(l, r, w));
    }
    return 0;
}

posted @ 2018-09-17 11:06  Garen-Wang  阅读(148)  评论(0编辑  收藏  举报