首页 > 代码库 > 分块入门题

分块入门题

分块入门题-(摘自黄学长的blog)

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

 

n<=100000其实是为了区分暴力和一些常数较大的写法。

接着第二题的解法,其实只要把块内查询的二分稍作修改即可。

不过这题其实想表达:可以在块内维护其它结构使其更具有拓展性,比如放一个 set ,这样如果还有插入、删除元素的操作,会更加的方便。

 

分块的调试检测技巧:

可以生成一些大数据,然后用两份分块大小不同的代码来对拍,还可以根据运行时间尝试调整分块大小,减小常数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
int blo,bl[100005],v[100005],n,lazy[1005];
long long read()
{
    long long x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
set<int> st[1005];
void clear(int x)
{
    st[x].clear();
    for(int i=(x-1)*blo+1;i<=min(n,x*blo);i++)
    st[x].insert(v[i]);
    //sort(st[x].begin(),st[x].end());
}
void change(int l,int r,int val)
{
    for(int i=l;i<=min(bl[l]*blo,r);i++)
    v[i]+=val;
    clear(bl[l]);
    if(bl[l]!=bl[r])
    {
        for(int i=r;i>=(bl[r]-1)*blo+1;i--)
        v[i]+=val;
        clear(bl[r]);
    }
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
    lazy[i]+=val;
}
void query(int l,int r,int x)
{
    int ans=-1;
    for(int i=l;i<=min(bl[l]*blo,r);i++)
    if(v[i]+lazy[bl[l]]<x)
    ans=max(ans,v[i]+lazy[bl[l]]);
    if(bl[l]!=bl[r])
    {
        for(int i=r;i>=(bl[r]-1)*blo+1;i--)
        if(v[i]+lazy[bl[r]]<x)
        ans-max(ans,v[i])+lazy[bl[r]];
    }
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
    {
        int c=x-lazy[i];
        set<int>::iterator it1=st[i].lower_bound(c);
        if(st[i].begin()==it1) continue;
        it1--;
        ans=max(ans,*it1+lazy[i]);
    }
    if(ans==-1) printf("impossible\n");else
    printf("%d\n",ans);
}
int main()
{    n=read();
    blo=sqrt(n);
    for(int i=1;i<=n;i++)
    v[i]=read(),bl[i]=(i-1)/blo+1,st[bl[i]].insert(v[i]);
    //for(int i=1;i<=bl[n];i++)
    //sort(st[i].begin(),st[i].end());
    char char_[10];
    for(int i=1;i<=n;i++)
    {
        scanf("%s",&char_);
        if(char_[0]==c)
        {
            int l,r,val;
            scanf("%d %d %d",&l,&r,&val);
            change(l,r,val);
        }else{
            int l,r,x;
            scanf("%d %d %d",&l,&r,&x);
            query(l,r,x);
        }
    }
    return 0;
}

 

分块入门题