ACM入门之【分块习题】

6277. 数列分块入门 1【区间修改 单点查询】

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long int LL;
LL a[N], ad[N], id[N], n, m, len;
//ad[i] 编号为i的块加的总数 id[i] i所对应的块
void add(int l, int r, int v) 
{
    
    
    for (int i = l; i <= min(r * 1ll, id[l]*len); i++) a[i] += v; //开头的不完整的
    if (id[l] == id[r]) return;//在一个块里
    for (int i = id[l] + 1; i <= id[r] - 1; i++) ad[i] += v;//中间完整的块
    for (int i = (id[r] - 1) * len + 1; i <= r; i++) a[i] += v;//结束不完整的
}
LL query(int x) {
    
    
    return a[x] + ad[id[x]];
}
int main(void) {
    
    
    cin >> n ;
    len = sqrt(n);
    for (int i = 1; i <= n; i++) cin>>a[i];
    for (int i = 1; i <= n; i++) id[i]=(i-1)/len+1;
    for(int i = 1; i <= n; i++) 
    {
    
    
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if (op == 0) add(l, r, c);
        else cout << query(r) << endl;
    }
    return 0;
}

6278. 数列分块入门 2【区间加 区间查询小于x的个数】

在这里插入图片描述
对于每一个块二分,可以快速的求出一个块内小于x的个数。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],ad[N],id[N],n,len;
vector<LL>ve[N];
void solve(int x)
{
    
    
    ve[x].clear();
    for(int i=(x-1)*len+1;i<=min(x*len,n);i++) ve[x].push_back(a[i]);
    sort(ve[x].begin(),ve[x].end());
}
void add(LL l,LL r,LL c)
{
    
    
    for(int i=l;i<=min(r,id[l]*len);i++) a[i]+=c;
    solve(id[l]);
    if(id[l]==id[r]) return;
    for(int i=id[l]+1;i<=id[r]-1;i++) ad[i]+=c;
    for(int i=(id[r]-1)*len+1;i<=r;i++) a[i]+=c;
    solve(id[r]);
}
LL query(LL l,LL r,LL x)
{
    
    
    int ans=0;
    for(int i=l;i<=min(r,id[l]*len);i++) if(a[i]+ad[id[i]]<x) ans++;
    if(id[l]==id[r]) return ans;
    for(int i=id[l]+1;i<=id[r]-1;i++)
    {
    
    
        int c=x-ad[i];
        ans+=lower_bound(ve[i].begin(),ve[i].end(),c)-ve[i].begin();
    }
    for(int i=(id[r]-1)*len+1;i<=r;i++) if(a[i]+ad[id[i]]<x) ans++;
    return ans;
}
int main(void)
{
    
    
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    len=sqrt(n);
    for(int i=1;i<=n;i++)
    {
    
    
        id[i]=(i-1)/len+1;
        ve[id[i]].push_back(a[i]);
    }
    for(int i=1;i<=id[n];i++) sort(ve[i].begin(),ve[i].end());
    for(int i=0;i<n;i++)
    {
    
    
        int op,l,r,c; cin>>op>>l>>r>>c;
        if(!op) add(l,r,c);
        else cout<<query(l,r,c*c)<<endl;
    }
    return 0;
}

6279. 数列分块入门 3【区间修改 区间查询小于x的最大值】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],ad[N],id[N],n,len;
vector<LL>ve[N];
void solve(int x)
{
    
    
    ve[x].clear();
    for(int i=(x-1)*len+1;i<=min(x*len,n);i++) ve[x].push_back(a[i]);
    sort(ve[x].begin(),ve[x].end());
}
void add(LL l,LL r,LL c)
{
    
    
    for(int i=l;i<=min(r,id[l]*len);i++) a[i]+=c;
    solve(id[l]);
    if(id[l]==id[r]) return;
    for(int i=id[l]+1;i<=id[r]-1;i++) ad[i]+=c;
    for(int i=(id[r]-1)*len+1;i<=r;i++) a[i]+=c;
    solve(id[r]);
}
LL query(LL l,LL r,LL x)
{
    
    
    LL ans=-1e18;
    for(int i=l;i<=min(r,id[l]*len);i++) 
        if(a[i]+ad[id[i]]<x) ans=max(ans,a[i]+ad[id[i]]);
    if(id[l]==id[r])
    {
    
    
         if(ans==-1e18) return -1;
        return ans;
    }
    for(int i=id[l]+1;i<=id[r]-1;i++)
    {
    
    
        LL c=x-ad[i];
        int index=lower_bound(ve[i].begin(),ve[i].end(),c)-ve[i].begin();
        index--;
        if(index>=0) ans=max(ans,ve[i][index]+ad[i]);
    }
    for(int i=(id[r]-1)*len+1;i<=r;i++) if(a[i]+ad[id[i]]<x) ans=max(ans,a[i]+ad[id[i]]);
    if(ans==-1e18) return -1;
    return ans;
}
int main(void)
{
    
    
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    len=sqrt(n);
    for(int i=1;i<=n;i++)
    {
    
    
        id[i]=(i-1)/len+1;
        ve[id[i]].push_back(a[i]);
    }
    for(int i=1;i<=id[n];i++) sort(ve[i].begin(),ve[i].end());
    for(int i=0;i<n;i++)
    {
    
    
        int op,l,r,c; cin>>op>>l>>r>>c;
        if(!op) add(l,r,c);
        else cout<<query(l,r,c)<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46527915/article/details/123749363