P2801 教主的魔法(分块)

· · 个人记录

题意:https://www.luogu.org/problem/P2801

考虑分块,在块内排序,维护块的加法tag,修改时小块暴力改,大块维护tag(不用排序,块内大小关系不变),查询时散块暴力找,大块二分位置

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
const int maxt=1010;
int n,m,t,cnt;
int a[maxn],b[maxn],L[maxn],R[maxn],pos[maxn],tag[maxt];
inline char readc()
{
    char c=0;while(c!='M'&&c!='A')c=getchar();
    return c;
}
inline void change(int ql,int qr,int k)
{
    if(pos[ql]==pos[qr])
    {
        for(int i=ql;i<=qr;i++)a[i]+=k;
        for(int i=L[pos[ql]];i<=R[pos[qr]];i++)b[i]=a[i];
        sort(b+L[pos[ql]],b+R[pos[qr]]+1);
        return;
    }
    for(int i=ql;i<=R[pos[ql]];i++)a[i]+=k;
    for(int i=L[pos[ql]];i<=R[pos[ql]];i++)b[i]=a[i];
    sort(b+L[pos[ql]],b+R[pos[ql]]+1);
    for(int i=L[pos[qr]];i<=qr;i++)a[i]+=k;
    for(int i=L[pos[qr]];i<=R[pos[qr]];i++)b[i]=a[i];
    sort(b+L[pos[qr]],b+R[pos[qr]]+1);
    for(int i=pos[ql]+1;i<=pos[qr]-1;i++)tag[i]+=k;
}
inline int query(int ql,int qr,int k)
{
    int ans=0;
    if(pos[ql]==pos[qr])
    {
        for(int i=ql;i<=qr;i++)if(a[i]+tag[pos[ql]]>=k)ans++;
        return ans;
    }
    for(int i=ql;i<=R[pos[ql]];i++)if(tag[pos[ql]]+a[i]>=k)ans++;
    for(int i=L[pos[qr]];i<=qr;i++)if(tag[pos[qr]]+a[i]>=k)ans++;
    for(int i=pos[ql]+1;i<=pos[qr]-1;i++)
    {
        int l=L[i],r=R[i],res=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(b[mid]+tag[i]>=k)res=R[i]-mid+1,r=mid-1;
            else l=mid+1;
        }
        ans+=res;
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);t=sqrt(n);cnt=n/t;
    if(n%t)cnt++;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
    for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=i*t;
    R[cnt]=n;
    for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1;
    for(int i=1;i<=cnt;i++)sort(b+L[i],b+R[i]+1);
    for(int i=1;i<=m;i++)
    {
        char op=readc();
        int l,r,k;scanf("%d%d%d",&l,&r,&k);
        if(op=='M')change(l,r,k);
        else printf("%d\n",query(l,r,k));
    }
    return 0;
}