[bzoj] 3343 教主的魔法 || 带修改分块

本文介绍了一种处理区间加法及区间内大于特定值元素数量查询的算法实现。通过使用lazy数组来标记区间操作,避免了重复计算,提高了效率。文章提供了一个具体的C++代码示例,展示了如何有效地进行区间操作及查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题

长度为n的序列,有两种操作:
1、[l,r]区间每个数+w
2、询问[l,r]区间有多少个数>c


记录lazy数组即可。

#include<cstdio>
#include<algorithm>
#define N 1000010
#define B 1010
#define st(x) (((x)-1)*B+1)
#define ed(x) min((x)*B,n)
#define bel(x) (((x)-1)/B+1)
using namespace std;
int n,q,l,r,w,a[N],s[N],lz[N];
char b[3];

int read()
{
    int ans=0,fu=1;
    char j=getchar();
    for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
    for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
    return ans*fu;
}

void push(int x)
{
    if (!lz[x]) return ;
    for (int i=st(x);i<=ed(x);i++)
    s[i]+=lz[x],a[i]+=lz[x];
    lz[x]=0;
}

void single_change(int l,int r,int w)
{
    int b=bel(l);
    push(b);
    for (int i=l;i<=r;i++) a[i]+=w;
    for (int i=st(b);i<=ed(b);i++) s[i]=a[i];
    sort(s+st(b),s+ed(b)+1);
}

void change(int l,int r,int w)
{
    if (bel(l)==bel(r)) return single_change(l,r,w);
    for (int i=bel(l)+1;i<bel(r);i++)
    lz[i]+=w;
    single_change(l,ed(bel(l)),w);
    single_change(st(bel(r)),r,w);
}

int block_query(int b,int w)
{
    return s+ed(b)-upper_bound(s+st(b),s+ed(b)+1,w-lz[b]-1)+1;
}

int single_query(int l,int r,int w)
{
    int b=bel(l),ret=0;
    for (int i=l;i<=r;i++)
    if (a[i]+lz[b]>=w) ret++;
    return ret;
}

int query(int l,int r,int w)
{
    if (bel(l)==bel(r)) return single_query(l,r,w);
    int ret=0;
    for (int i=bel(l)+1;i<bel(r);i++)
    ret+=block_query(i,w);
    return ret+single_query(l,ed(bel(l)),w)+single_query(st(bel(r)),r,w);
}

int main()
{
    n=read();
    q=read();
    for (int i=1;i<=n;i++)
    a[i]=s[i]=read();
    for (int i=1;st(i)<=n;i++) sort(s+st(i),s+ed(i)+1);
    while (q--)
    {
    scanf("%s",b);
    l=read();
    r=read();
    w=read();
    if (b[0]=='M') change(l,r,w);
    else printf("%d\n",query(l,r,w));
    }
    return 0;
}

转载于:https://www.cnblogs.com/mrha/p/8185460.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值