洛谷 P2801 教主的魔法 解题报告

P2801 教主的魔法

题目描述

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给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的英雄数。

数据范围

对30%的数据,N≤1000,Q≤1000。

对100%的数据,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000。


考虑使用分块维护

发现没有添加或者删除,我们可以不写分裂合并

我们可以维护\(D\)个块,每个块大小为\(S\)

我们保证每个块都是有序的,这样

在查询的时候,边角直接暴力,整块二分即可

在修改的时候,边角直接暴力,整块打标记

发现单次操作的复杂度大概是\(O(DlogS+S)\)的

我们可以把块放的稍稍比\(\sqrt N\)大一点之类的


Code:

#include <cstdio>
#include <algorithm>
#include <cmath>
const int S=1e3+10;
const int N=1e6+10;
struct node
{
int pos,dat;
bool friend operator <(node n1,node n2)
{
return n1.dat<n2.dat;
}
}t[N];
int belong[N],L[S],R[S],lazy[S],delta[S],n,m,si,s;
void init()
{
scanf("%d%d",&n,&m);
s=sqrt(n);
for(int i=1;i<=n;i++)
scanf("%d",&t[i].dat);
for(si=1;si*s<=n;si++)
{
L[si]=(si-1)*s+1,R[si]=si*s;
for(int j=L[si];j<=R[si];j++)
belong[j]=si,t[j].pos=j;
}
if(R[si]<n)
{
L[si]=R[si-1]+1,R[si]=n;
for(int j=L[si];j<=R[si];j++)
belong[j]=si,t[j].pos=j;
}
L[si+1]=R[si]+1;
for(int i=1;i<=si;i++)
std::sort(t+L[i],t+R[i]+1);
}
void change(int l,int r,int w)
{
if(belong[l]==belong[r])
{
int now=belong[l];
for(int i=L[now];i<=R[now];i++)
if(t[i].pos<=r&&t[i].pos>=l)
t[i].dat+=w;
std::sort(t+L[now],t+R[now]+1);
}
else
{
for(int i=belong[l]+1;i<belong[r];i++)
delta[i]+=w;
int now=belong[l];
for(int i=L[now];i<=R[now];i++)
if(t[i].pos>=l)
t[i].dat+=w;
std::sort(t+L[now],t+R[now]+1);
now=belong[r];
for(int i=L[now];i<=R[now];i++)
if(t[i].pos<=r)
t[i].dat+=w;
std::sort(t+L[now],t+R[now]+1);
}
}
int query(int l,int r,int w)
{
int sum=0;
if(belong[l]==belong[r])
{
int now=belong[l];
for(int i=L[now];i<=R[now];i++)
if(t[i].pos>=l&&t[i].pos<=r&&t[i].dat+delta[now]>=w)
++sum;
}
else
{
for(int i=belong[l]+1;i<belong[r];i++)
{
int ll=L[i]-1,rr=R[i],tmp=t[ll].dat;
t[ll].dat=0;
while(ll<rr)
{
int mid=ll+rr+1>>1;
if(t[mid].dat+delta[i]<w)
ll=mid;
else
rr=mid-1;
}
sum+=R[i]-ll;t[L[i]-1].dat=tmp;
}
int now=belong[l];
for(int i=L[now];i<=R[now];i++)
if(t[i].pos>=l&&t[i].dat+delta[now]>=w)
++sum;
now=belong[r];
for(int i=L[now];i<=R[now];i++)
if(t[i].pos<=r&&t[i].dat+delta[now]>=w)
++sum;
}
return sum;
}
void work()
{
char c[3];
for(int l,r,w,i=1;i<=m;i++)
{
scanf("\n%c%d%d%d",c,&l,&r,&w);
if(c[0]=='M') change(l,r,w);
else printf("%d\n",query(l,r,w));
}
}
int main()
{
init();
work();
return 0;
}

2018.8.25

上一篇:Eclipse Android HH and theme


下一篇:洛谷P2801 教主的魔法 [分块,二分答案]