博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj3343】教主的魔法 分块+二分
阅读量:5327 次
发布时间:2019-06-14

本文共 2270 字,大约阅读时间需要 7 分钟。

题目描述

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N
每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[LR](1≤LRN)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第LR)个英雄的身高)
CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [LR] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
WD巨懒,于是他把这个回答的任务交给了你。

输入

第1行为两个整数NQQ为问题数与教主的施法数总和。
第2行有N个正整数,第i个数代表第i个英雄的身高。
第3到第Q+2行每行有一个操作:
(1)若第一个字母为“M”,则紧接着有三个数字LRW。表示对闭区间 [LR] 内所有英雄的身高加上W
(2)若第一个字母为“A”,则紧接着有三个数字LRC。询问闭区间 [LR] 内有多少英雄的身高大于等于C

输出

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

样例输入

5 3

1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4

样例输出

2

3


题解

分块+二分

分成√n 个块,对于每个块另开一个数组将h[i]排序。

修改时,整块直接打add标记,多余部分暴力改,然后重排序。

查询时,整块使用排序后的数组二分查找大于等于c-add的个数,多余部分暴力查询。

注意l和r同块时的特判。

#include 
#include
#include
using namespace std;int n , si , h[1000010] , v[1000010] , add[1010];char str[5];void reset(int b){ int i , l = b * si , r = min((b + 1) * si - 1 , n - 1); for(i = l ; i <= r ; i ++ ) v[i] = h[i]; sort(v + l , v + r + 1);}int search(int b , int lim){ int l = b * si , r = min((b + 1) * si - 1 , n - 1) , mid , ans = r + 1 , tr = r; while(l <= r) { mid = (l + r) >> 1; if(v[mid] + add[b] >= lim) ans = mid , r = mid - 1; else l = mid + 1; } return tr - ans + 1;}int main(){ int m , i , l , r , x , ans; scanf("%d%d" , &n , &m); si = (int)sqrt(n); for(i = 0 ; i < n ; i ++ ) scanf("%d" , &h[i]); for(i = 0 ; i * si < n ; i ++ ) reset(i); while(m -- ) { scanf("%s%d%d%d" , str , &l , &r , &x); l -- , r -- ; if(str[0] == 'M') { if(l / si == r / si) { for(i = l ; i <= r ; i ++ ) h[i] += x; reset(l / si); } else { for(i = l / si + 1 ; i < r / si ; i ++ ) add[i] += x; for(i = l ; i < (l / si + 1) * si ; i ++ ) h[i] += x; for(i = r / si * si ; i <= r ; i ++ ) h[i] += x; reset(l / si) , reset(r / si); } } else { ans = 0; if(l / si == r / si) for(i = l ; i <= r ; i ++ ) ans += (h[i] + add[l / si] >= x); else { for(i = l / si + 1 ; i < r / si ; i ++ ) ans += search(i , x); for(i = l ; i < (l / si + 1) * si ; i ++ ) ans += (h[i] + add[l / si] >= x); for(i = r / si * si ; i <= r ; i ++ ) ans += (h[i] + add[r / si] >= x); } printf("%d\n" , ans); } } return 0;}

 

转载于:https://www.cnblogs.com/GXZlegend/p/6591298.html

你可能感兴趣的文章
字符串类型的相互转换
查看>>
基础学习:C#中float的取值范围和精度
查看>>
Vim配置Node.js开发工具
查看>>
web前端面试题2017
查看>>
ELMAH——可插拔错误日志工具
查看>>
MySQL学习笔记(四)
查看>>
【Crash Course Psychology】2. Research & Experimentation笔记
查看>>
SOPC Builder中SystemID
查看>>
关于 linux 的 limit 的设置
查看>>
HDU(4528),BFS,2013腾讯编程马拉松初赛第五场(3月25日)
查看>>
vim中文帮助教程
查看>>
MySQL基础3
查看>>
RxJS & Angular
查看>>
面向对象(多异常的声明与处理)
查看>>
MTK笔记
查看>>
ERROR: duplicate key value violates unique constraint "xxx"
查看>>
激活office 365 的启动文件
查看>>
无法根据中文查找
查看>>
[简讯]phpMyAdmin项目已迁移至GitHub
查看>>
转载 python多重继承C3算法
查看>>