#6278. 数列分块入门 2

#6278. 数列分块入门 2

内存限制:256 MiB时间限制:500 ms标准输入输出

题目描述

给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 x 的元素个数。

输入格式

第一行输入一个数字 n。

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

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

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

若 opt=1,表示询问 [l,r] 中,小于 c^2​​ 的数字的个数。

输出格式

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

样例输入

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

样例输出

3
0
2
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4+7;
#define ll long long
int a[maxn],belong[maxn],l[maxn],r[maxn],sum[maxn];
int block,num,n;
vector<int>v[maxn]; //用于排序
inline int read()
{
    char ch = getchar(); int x = 0, f = 1;
    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    while('0' <= ch && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
void build() //初始化
{
    block = 0.5 * sqrt(n); //0.5比较快
    num = n / block; if(n % block) num++;
    for(int i = 1; i <= n; i++) a[i] = read();
    for(int i = 1; i <= num; i++)
        l[i] = (i - 1) * block + 1, r[i] = i * block;
    r[num] = n;
    for(int i = 1; i <= n; i++)
    {
        belong[i] = (i - 1) / block + 1;
        v[belong[i]].push_back(a[i]);
    }
    for(int i = 1; i <= belong[n]; i++)
        sort(v[i].begin(),v[i].end());
}

void reset(int x)//对第x个分块整体排序
{
    v[x].clear();
    for(int i = l[x]; i <= min(r[x],n); i++)
        v[x].push_back(a[i]);
    sort(v[x].begin(),v[x].end());
}

void update(int x, int y, int c)
{
    int t1 = belong[x], t2 = belong[y];
    for(int i = x; i <= min(r[t1], y); i++) //对左区间
    //对第一个不完整区间暴力加法,分为t1==t2||t1!=t2,就是两种合在一起,所以有了min
        a[i] += c;
    reset(t1); //对一个修改区间排序
    if(t1 != t2) for(int i = l[t2]; i <= y; i++) //对右区间
        a[i] += c;
    reset(t2); //对最后一个区间排序
    for(int i = t1 + 1; i < t2; i++) sum[i] += c; //块内的
}

int query(int x, int y, ll c)
{
    int t1 = belong[x], t2 = belong[y];
    int ans = 0;
    for(int i = x; i <= min(r[t1], y); i++) //左区间查询
        if(a[i] + sum[t1] < c) ans++;

    if(t1 != t2)for(int i = l[t2]; i <= y; i++) //右区间查询
        if(a[i] + sum[t2] < c) ans++;

    for(int i = t1 + 1; i < t2; i++) //块内查询
    {
        ll temp = c - sum[i];
        ans += lower_bound(v[i].begin(),v[i].end(),temp)-v[i].begin();
    }
    return ans;
}

int main()
{
    n = read(); build();
    for(int i = 1; i <= n; i++)
    {
        int op, l, r, c;
        op = read(); l = read(); r = read(); c = read();
        if(op == 0) update(l, r, c);
        else printf("%d\n", query(l,r,c*c));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sugarbliss/article/details/81207075