1. 程式人生 > 其它 >loj6277~6285.分塊入門九講

loj6277~6285.分塊入門九講

loj6278.數列分塊入門 2

序列支援區間加,區間查詢小於一個數的個數。

先思考怎樣維護答案。可以分塊後對每個塊維護一個 \(vector\),裡面是塊內排序後的結果。

修改的時候整塊直接打標記,散塊暴力重構一遍。

查詢整塊用 lower_bound,散塊暴力查詢。

塊大小 \(\sqrt n\) 時,複雜度 \(O(n\sqrt n\log n)\),還不夠優秀。

考慮調整塊大小。設塊大小為 \(B\) 發現每次操作的運算次數是 \(B\log n+\frac n B\geq 2\sqrt{n\log n}\),取等條件是 \(B\log n=\frac n B\),解得 \(B=\sqrt{\frac n{\log n}}\)

,此時複雜度優化為 \(O(n\sqrt{n\log n})\),實測結果比前一種快了一半以上。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
#define int long long
int n,block,a[500001],b[500001],tag[500001];
vector<int> v[500001];
inline int read()
{
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void rebuild(int k,int l,int r,int x)
{
    v[k].clear();
    for(register int i=block*(k-1)+1;i<=min(block*k,n);++i)
        a[i]+=tag[k];
    for(register int i=l;i<=r;++i)
        a[i]+=x;
    for(register int i=block*(k-1)+1;i<=min(block*k,n);++i)
        v[k].push_back(a[i]);
    sort(v[k].begin(),v[k].end());
    tag[k]=0;
}
inline int query(int k,int l,int r,int x)
{
    int res=0;
    for(register int i=l;i<=r;++i)
        res+=(a[i]+tag[k])<x;
    return res;
}
signed main()
{
    n=read();
    block=sqrt(n/log2(n));
    for(register int i=1;i<=n;++i)
    {
        a[i]=read();
        b[i]=(i-1)/block+1;
        v[b[i]].push_back(a[i]);
    }
    for(register int i=1;i<=b[n];++i)
        sort(v[i].begin(),v[i].end());
    for(register int i=1;i<=n;++i)
    {
        int opt=read(),l=read(),r=read(),x=read();
        int bl=(l-1)/block+1,br=(r-1)/block+1;
        if(opt==0)
        {
            if(bl==br)
            {
                rebuild(bl,l,r,x);
                continue;
            }
            for(register int j=bl+1;j<br;++j)
                tag[j]+=x;
            rebuild(bl,l,block*bl,x);
            rebuild(br,block*(br-1)+1,r,x);
        }
        if(opt==1)
        {
            x*=x;
            if(bl==br)
            {
                printf("%lld\n",query(bl,l,r,x));
                continue;
            }
            int ans=0;
            for(register int j=bl+1;j<br;++j)
                ans+=lower_bound(v[j].begin(),v[j].end(),x-tag[j])-v[j].begin();
            printf("%lld\n",ans+query(bl,l,block*bl,x)+query(br,block*(br-1)+1,r,x));
        }
    }
    return 0;
}