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

洛谷 P2801 教主的魔法 解题报告的更多相关文章

  1. 洛谷——P2801 教主的魔法(线段树or分块)

    P2801 教主的魔法 (1) 若第一个字母为“M”,则紧接着有三个数字L.R.W.表示对闭区间 [L, R] 内所有英雄的身高加上W. (2) 若第一个字母为“A”,则紧接着有三个数字L.R.C.询 ...

  2. 洛谷P2801 教主的魔法 [分块,二分答案]

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

  3. 洛谷P2801 教主的魔法 分块

    正解:分块 解题报告: 哇之前的坑还没填完就又写新博客? 不管不管,之前欠的两三篇题解大概圣诞节之前会再仔细想想然后重新写下题解趴,确实还挺难的感觉没有很好的理解呢QAQ还是太囫囵吞枣不求甚解了,这样 ...

  4. 洛谷 P2801 教主的魔法

    题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是 ...

  5. BZOJ——3343: 教主的魔法 || 洛谷—— P2801 教主的魔法

    http://www.lydsy.com/JudgeOnline/problem.php?id=3343  ||  https://www.luogu.org/problem/show?pid=280 ...

  6. 洛谷 P2797 Facer的魔法 解题报告

    P2797 Facer的魔法 题意:给你n个数,你可以选若干个数,使得平均数减中位数最大 数据范围:\(n \le 10^5\) 原题CF626E 很容易想到枚举一个中位数,但是如果选取的数字的个数是 ...

  7. [洛谷P2801]教主的魔法

    题目大意:有$n$个数,$q$个操作.两种操作: $M\;l\;r\;w:$把$[l,r]$所有数加上$w$ $A\;l\;r\;c:$查询$[l,r]$内大于等于$c$的元素的个数. 题解:分块,对 ...

  8. 洛谷 P2801 教主的魔法 题解

    题面 刚看到这道题的时候用了个树状数组优化前缀和差分的常数优化竟然AC了?(这数据也太水了吧~) 本人做的第一道分块题,调试了好久好久,最后竟然没想到二分上还会出错!(一定要注意)仅此纪念: #inc ...

  9. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

随机推荐

  1. hadoop生态搭建(3节点)-06.hbase配置

    # http://archive.apache.org/dist/hbase/1.2.4/ # ==================================================== ...

  2. Static关键字,遇到的问题_1

    一.问题 父类代码:                                                                                          ...

  3. C++ vector的reserve和resize详解

    vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!原因如下:      rese ...

  4. Messy Code in Windows Server 2008 R2 English Edition

          We always use Windows Server 2008 R2 English operation system. And it doesn't have any problem ...

  5. 【个人训练】(POJ1276)Cash Machine

    最近的很多题解应该都是dp相关的了,emmm因为dp对我而言思考难度比较大,那么为了理顺自己的思路当然只能通过写blog整理了.愿我能成功搞定dp这个大关!(至少中等难度的dp要能够解决啊o(TヘTo ...

  6. Qt Qwdget 汽车仪表知识点拆解7 图像绘制,旋转

    先贴上效果图,注意,没有写逻辑,都是乱动的 看下最中心的指针旋转,这里使用的QPainter的绘制函数 要显示复杂的效果,需要分层 void Widget::draw_number_pointer() ...

  7. ADB常用指令

    adb 命令是adb程序自带的一些命令:adb shell则是调用Android系统的命令,Android系统特有的命令都放在Android设备的/system/bin目录中 MonkeyRunner ...

  8. Lua工具类

    1.打印table --一个用以打印table的函数 function print_r (t, name) print(pr(t,name)) end function pr (t, name, in ...

  9. 【转】Linux学习(1)-常用快捷键、文件管理和查询

    原文链接:http://www.cnblogs.com/zhaopei/p/7397402.html 有话要说 为什么要用Linux?要用Linux的原因太多,想说说不完啊. 如果你说用Linux只是 ...

  10. python 基础篇 13 迭代器与生成器

    13. 前⽅⾼能-迭代器和⽣成器本节主要内容:1. 迭代器2. ⽣成器 ⼀. 迭代器我们之前⼀直在⽤可迭代对象进⾏迭代操作. 那么到底什么是可迭代对象. 本⼩节主要讨论可迭代对象. ⾸先我们先回顾⼀下 ...