分块

数列分块入门训练集:


讲解

入门2:

求出小于每个数的个数,维持块内有序,进行二分。

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<ll,int>P;
const int N=5e4+5;
vector<ll>v[N];
int L[N],R[N],belong[N];
ll d[N],lazy[N];
int block,num;
void read(int &x)
{
    x=0;
    int f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    x*=f;
}
void solve(int p)
{
    v[p].clear();
    for(int i=L[p];i<=R[p];i++)
        v[p].pb(d[i]);
    sort(v[p].begin(),v[p].end());
}
void build(int n)
{
    block=sqrt(n);
    num=n/block;
    if(n%block)
        num++;
    for(int i=1;i<=num;i++)
        L[i]=(i-1)*block+1,R[i]=block*i;
    R[num]=n;
    for(int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;
    memset(lazy,0,sizeof(lazy));
}
void update(int l,int r,int c)
{
    int p=belong[l];
    int q=belong[r];
    if(p==q)
    {
        for(int i=l;i<=r;i++)
            d[i]+=c;
        solve(p);
    }
    else
    {
        for(int i=p+1;i<q;i++)
            lazy[i]+=c;
        for(int i=l;i<=R[p];i++)
            d[i]+=c;
        solve(p);
        for(int i=L[q];i<=r;i++)
            d[i]+=c;
        solve(q);
    }
}
int query(int l,int r,int c)
{
    ll t=1LL*c*c;
    int res=0,p=belong[l],q=belong[r];
    if(p==q)
    {
        for(int i=l;i<=r;i++)
        {
            if(d[i]<t-lazy[p])
                res++;
        }
    }
    else
    {
        for(int i=p+1;i<q;i++)
        {
            int m=lower_bound(v[i].begin(),v[i].end(),t-lazy[i])-v[i].begin();
            res+=m;
        }
        for(int i=l;i<=R[p];i++)
        {
            if(d[i]<t-lazy[p])
                res++;
        }
        for(int i=L[q];i<=r;i++)
        {
            if(d[i]<t-lazy[q])
                res++;
        }
    }
    return res;
}
int main()
{
    int n,x;
    read(n);
    build(n);
    for(int i=1;i<=n;i++)
    {
        read(x);
        d[i]=x;
        v[belong[i]].pb(x);
    }
    for(int i=1;i<=num;i++)
        sort(v[i].begin(),v[i].end());
    int op,l,r,c;
    for(int i=1;i<=n;i++)
    {
        read(op);
        read(l);
        read(r);
        read(c);
        if(op==0)
            update(l,r,c);
        else
            printf("%d\n",query(l,r,c));
    }
    return 0;
}

楼房重建 HYSBZ - 2957:

分析:

维护每个块的最大斜率值和块内呈递增的高度序列,每次更新时,重新维护序列。
复杂度:\(O(m*(\sqrt{n}+num*log(\sqrt{n})))\)

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1e5+5;
const int maxn=1005;
double hm[maxn],h[N];
vector<double>v[maxn];
int block,num;
int belong[N],L[maxn],R[maxn];
void build(int n)
{
    block=sqrt(n);
    num=n/block;
    if(n%block)
        num++;
    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;
}
void update(int x,int y)
{
    int p=belong[x];
    v[p].clear();
    h[x]=1.0*y/x;
    double m=0;
    for(int i=L[p];i<=R[p];i++)
    {
        if(h[i]>m)
        {
            v[p].pb(h[i]);
            m=h[i];
        }
    }
    hm[p]=m;
}
int query()
{
    int res=0;
    double m=0;
    for(int i=1;i<=num;i++)
    {
        int t=upper_bound(v[i].begin(),v[i].end(),m)-v[i].begin();
        res+=(v[i].size()-t);
        if(hm[i]>m)//注意
            m=hm[i];
    }
    return res;
}
int main()
{
    int n,m,x,y;
    scanf("%d%d",&n,&m);
    build(n);
    while(m--)
    {
        scanf("%d%d",&x,&y);
        update(x,y);
        printf("%d\n",query());
    }
    return 0;
}

posted @ 2020-03-14 18:10  xzx9  阅读(127)  评论(0编辑  收藏  举报