LOJ 分块入门1-9

题目链接
看这篇学习

分块入门1


给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值。

代码:

#include 
#include 
#define min(a,b) (a

分块入门2


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

#include 
#include 
#include 
#include 
using namespace std;

int n, blo, bl[50005], v[50005], tag[305];
vector fuck[305];

void reset(int k)
{
    fuck[k].clear();
    for(int i = min(k*blo,n); i > (k-1)*blo; --i) fuck[k].push_back(v[i]);
    sort(fuck[k].begin(), fuck[k].end());
}

void add(int l, int r, int c)
{
    for(int i = min(bl[l]*blo, r); i >= l; --i) v[i] += c;
    reset(bl[l]);
    if(bl[l] != bl[r])
    {
        for(int i = (bl[r]-1)*blo+1; i <= r; ++i)
            v[i] += c;
        reset(bl[r]);
    }
    for(int i = bl[l]+1; i < bl[r]; ++i) tag[i] += c;
}

int query(int l, int r, int c)
{
    int ans = 0;
    for(int i = min(bl[l]*blo, r); i >= l; --i) if(v[i] + tag[bl[l]] < c) ++ans;
    if(bl[l] != bl[r])
    {
        for(int i = (bl[r]-1)*blo+1; i <= r; ++i) if(v[i] + tag[bl[r]] < c) ++ans;
    }
    for(int i = bl[l]+1; i < bl[r]; ++i)
    {
        ans += lower_bound(fuck[i].begin(),fuck[i].end(),c-tag[i]) - fuck[i].begin();
    }
    return ans;
}

int main()
{
    scanf("%d",&n);
    blo = sqrt(n);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d",&v[i]);
        bl[i] = (i-1)/blo+1;
        fuck[bl[i]].push_back(v[i]);
    }
    for(int i = 1; i <= bl[n]; ++i) sort(fuck[i].begin(), fuck[i].end());
    for(int i = 0; i < n; ++i)
    {
        int opt, l, r, c;
        scanf("%d%d%d%d",&opt,&l,&r,&c);
        if(opt) printf("%d\n",query(l,r,c*c));
        else add(l,r,c);
    }
    return 0;
}

分块入门3


给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 x 的前驱(比其小的最大元素)。
代码:

#include 
#include 
#include 
using namespace std;

#define ll long long

ll n, blo, bl[1000005], v[1000005], tag[4005];
vector fuck[4005];

void reset(ll k)
{
    fuck[k].clear();
    for(ll i = min(k*blo,n); i > (k-1)*blo; --i) fuck[k].push_back(v[i]);
    sort(fuck[k].begin(), fuck[k].end());
}

void add(ll l, ll r, ll c)
{
    for(ll i = min(bl[l]*blo, r); i >= l; --i) v[i] += c;
    reset(bl[l]);
    if(bl[l] != bl[r])
    {
        for(ll i = (bl[r]-1)*blo+1; i <= r; ++i)
            v[i] += c;
        reset(bl[r]);
    }
    for(ll i = bl[l]+1; i < bl[r]; ++i) tag[i] += c;
}

ll query(ll l, ll r, ll c)
{
    ll ans = (1ll<<63);
    for(ll i = min(bl[l]*blo, r); i >= l; --i) if(v[i] + tag[bl[l]] > ans && v[i] + tag[bl[l]] < c) ans = v[i] + tag[bl[l]];
    if(bl[l] != bl[r])
    {
        for(ll i = (bl[r]-1)*blo+1; i <= r; ++i) if(v[i] + tag[bl[r]] > ans && v[i] + tag[bl[r]] < c) ans = v[i] + tag[bl[r]];
    }
    for(ll i = bl[l]+1; i < bl[r]; ++i)
    {
        ll mmp = lower_bound(fuck[i].begin(),fuck[i].end(),c-tag[i]) - fuck[i].begin()-1;
        if(~mmp && fuck[i][mmp]+tag[i] > ans) ans = fuck[i][mmp]+tag[i];
    }
    if(ans == (1ll<<63)) return -1;
    return ans;
}

int main()
{
    scanf("%lld",&n);
    blo = sqrt(n);
    for(ll i = 1; i <= n; ++i)
    {
        scanf("%lld",&v[i]);
        bl[i] = (i-1)/blo+1;
        fuck[bl[i]].push_back(v[i]);
    }
    for(ll i = 1; i <= bl[n]; ++i) sort(fuck[i].begin(), fuck[i].end());
    for(ll i = 0; i < n; ++i)
    {
        ll opt, l, r, c;
        scanf("%lld%lld%lld%lld",&opt,&l,&r,&c);
        if(opt) printf("%lld\n",query(l,r,c));
        else add(l,r,c);
    }
    return 0;
}

你可能感兴趣的:(分块)