教主的魔法(分块模板)

Posted hsez-cyx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了教主的魔法(分块模板)相关的知识,希望对你有一定的参考价值。

教主的魔法(luogu)

Description

题目描述

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。

每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)

CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。

WD巨懒,于是他把这个回答的任务交给了你。

输入格式

第1行为两个整数N、Q。Q为问题数与教主的施法数总和。

第2行有N个正整数,第i个数代表第i个英雄的身高。

第3到第Q+2行每行有一个操作:

(1) 若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。

(2) 若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。

输出格式

对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。

Solution

分块用于区间加减和区间查大于某数的数的个数模板

排序后二分

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
const int N=1e6+10,M=1e3+10;
struct node
{
    int l,r;
    ll tag;
}f[M];
//若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。
//若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。
int n,m,t,l,r,pos[N];
char s[5];
ll c,d[N],a[N];
void add(int l,int r,int c)
{
    int pl=pos[l],pr=pos[r];
    for(int i=pl;i<=pr;i++)
        f[i].tag+=c;
    if(l!=f[pl].l)
    {
        for(int i=f[pl].l;i<l;i++) d[i]-=c;
        for(int i=f[pl].l;i<=f[pl].r;i++) a[i]=d[i];
        sort(a+f[pl].l,a+f[pl].r+1);
    }
    if(r!=f[pr].r)
    {
        for(int i=r+1;i<=f[pr].r;i++) d[i]-=c;
        for(int i=f[pr].l;i<=f[pr].r;i++) a[i]=d[i];
        sort(a+f[pr].l,a+f[pr].r+1);
    }
}
int get(int l,int r,ll c)
{
    int ans=0;
    int pl=pos[l],pr=pos[r];
    for(int i=pl;i<=pr;i++)
    {
        int p=lower_bound(a+f[i].l,a+f[i].r+1,c-f[i].tag)-a;
        ans+=f[i].r+1-p;
    }
    for(int i=f[pl].l;i<l;i++)
        if(d[i]+f[pl].tag>=c) ans--;
    for(int i=r+1;i<=f[pr].r;i++)
        if(d[i]+f[pr].tag>=c) ans--;
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld",&d[i]),a[i]=d[i];
    t=sqrt(n);
    for(int i=1;i<=t;i++)
        f[i].l=(i-1)*t+1,f[i].r=i*t;
    if(f[t].r<n) f[++t].r=n,f[t].l=f[t-1].r+1;
    for(int i=1;i<=t;i++)
    {
        sort(a+f[i].l,a+f[i].r+1);
        for(int j=f[i].l;j<=f[i].r;j++)
            pos[j]=i;
    }
    while(m--)
    {
        scanf("%s%d%d%lld",s,&l,&r,&c);
        if(s[0]==M) add(l,r,c);
        else printf("%d
",get(l,r,c));
    }
    return 0;    
}

 

以上是关于教主的魔法(分块模板)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3343: 教主的魔法 分块

BZOJ 3343: 教主的魔法 [分块]学习笔记

教主的魔法[分块+二分]

BZOJ_3343_教主的魔法_分块+二分查找

每日题解 #16LGP2801 教主的魔法

BZOJ 3343:教主的魔法(分块)