LOJ 6278 数列分块入门 2

题目链接:https://loj.ac/problem/6278

解题思路:

分块维护区间递增序列。

对于修改,边界暴力后修改两个边界的递增序列使其正确,完整块打标记

对于询问,边界暴力+块内二分

修改的复杂度 O(sqrt(N) + 2*sqrt(N)*log(sqrtN))

询问复杂度    O (sqrt(N) + 2*sqrt(N))

所以整体大概是 O (q*sqrt(N)*log(sqrtN)) //玄学计算复杂度,不太准

所以分块大概是用来处理几万的数据量的。(5e4的数据什么的)

话不多说,直接看板子就得啦。(要交C++17才能过,不过代码本身应该是没问题的,自己测试过上面的数据了)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define pb push_back
#define ll long long
using namespace std;

const int N = 5e4+5;
const int M = 500;

int blo,n;
int bl[N];
ll a[N];
ll atag[M];
vector<ll>ve[M];

void reset(int x)
{
    ve[x].clear();
    for (int i=blo*(x-1)+1;i<=min(blo*x,n);i++){
        ve[x].pb(a[i]);
    }
    sort(ve[x].begin(),ve[x].end());
}

void modify(int l,int r,ll c)
{
    for (int i=l;i<=min(bl[l]*blo,r);i++)
        a[i] += c;
    reset(bl[l]);
    if (bl[l]!=bl[r]){
        for (int i=(bl[r]-1)*blo+1;i<=r;i++)
            a[i] += c;
        reset(bl[r]);
    }

    for (int i=bl[l]+1;i<=bl[r]-1;i++)
        atag[i] += c;
}

int query(int l,int r,ll c)
{
    int ans = 0;
    for (int i=l;i<=min(bl[l]*blo,r);i++)
        if (a[i]+atag[bl[l]]<c) ans++;
    //printf("ans=%d\n",ans);
    if (bl[l]!=bl[r]){
        for (int i=(bl[r]-1)*blo+1;i<=r;i++)
            if (a[i]+atag[bl[r]]<c) ans++;
    }//printf("ans=%d\n",ans);
    for (int i=bl[l]+1;i<=bl[r]-1;i++){
        ans += lower_bound(ve[i].begin(),ve[i].end(),c-atag[i]) - ve[i].begin();
    }//printf("ans=%d\n",ans);
    return ans;
}

int main()
{
/*
        freopen("C:/Users/DELL/Desktop/a1.in", "r", stdin);
        freopen("C:/Users/DELL/Desktop/my.out", "w", stdout);
*/
        scanf("%d",&n);
        blo = sqrt(n);
        ///init
        //for (int i=1;i<=(n-1)/blo+1;i++) ve[i].clear(),atag[i]=0;
        for (int i=1;i<M;i++){
            ve[i].clear();
            atag[i] = 0;
        }
        for (int i=1;i<=n;i++){
            scanf("%I64d",a+i);
            bl[i] = (i-1)/blo + 1;
            ve[bl[i]].pb(a[i]);
        }
        for (int i=1;i<=bl[n];i++) sort(ve[i].begin(),ve[i].end());
        int op,l,r;
        ll c;
        int q = n;
        while (q--){
            scanf("%d %d %d %I64d",&op,&l,&r,&c);
            if (op==0){
                modify(l,r,c);
/*
                for (int i=1;i<=n;i++){
                    printf("%I64d ",a[i]+atag[bl[i]]);
                    if (bl[i+1]!=bl[i]) printf("] [");
                }
                printf("\n");
*/
            }
            else printf("%d\n",query(l,r,c*c));
        }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43768644/article/details/94356281
今日推荐