「 Luogu P2801 」 教主的魔法——分块
# 解题思路
修改,就是一个区间修改的常规操作,但是为了迎合查询的需要,对两端的不完整的块需要暴力重构,重新进行排序操作,保证每一块都是单调上升的顺序。
然后再说进行查询的操作,起初,我们需要在每一个块内进行排序。保证顺序时单调上升的(在每一个块内,是独立的),然后查询的时候对每一块($k$)都二分查找到大于 $num + tag[k]$ 的第一个数的位置,然后就可以得到一共有多少大于 $num$ 的数了。
值得注意的是,有些题解写的是对原序列直接进行排序,这就有一个错误,那就是在排序之后序列的顺序改变,改变了之后在进行区间修改的时候就不能保证正确性了。
所以我们开一个 vector 将每个块内的数都存下来。我的代码 T 了一个点,但是了 O2 过了,懒得再去卡常了
# 附上代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 1e6+;
int N, Q, arr[maxn], in[maxn], cnt, tag[maxn];
vector<int> b[];
struct BLOCK {
template <typename T> inline void read(T &x) {
x = ; T f = ; char c = getchar();
while (c < '' || c > '') {if(c == '-') f = -; c = getchar();}
while (c <= '' && c >= '') {x = x* + c-''; c = getchar();}
x *= f;
}
void reset(int k) {
b[k].clear();
for(int i=(k-)*cnt+; i<=min(k*cnt, N); i++)
arr[i] += tag[k], b[k].push_back(arr[i]);
sort(b[k].begin(), b[k].end());
tag[k] = ;
}
void build() {
cnt = sqrt(N);
for(int i=; i<=N; i++) {
read(arr[i]);
in[i] = (i-)/cnt+;
b[in[i]].push_back(arr[i]);
}
for(int i=in[]; i<=in[N]; i++)
sort(b[i].begin(), b[i].end());
}
void update(int l, int r, int num) {
for(int i=l; i<=min(in[l]*cnt, r); i++)
arr[i] += num;
reset(in[l]);
if(in[l] != in[r]) {
for(int i=(in[r]-)*cnt+; i<=r; i++)
arr[i] += num;
reset(in[r]);
}
for(int i=in[l]+; i<in[r]; i++)
tag[i] += num;
}
int check(int k, int num) {
int ans = (b[k].end()-lower_bound(b[k].begin(), b[k].end(), num-tag[k]));
return ans;
}
int query(int l, int r, int num) {
int ans = ;
for(int i=l; i<=min(in[l]*cnt, r); i++)
if(arr[i] + tag[in[i]] >= num) ans ++;
if(in[l] != in[r]) {
for(int i=(in[r]-)*cnt+; i<=r; i++)
if(arr[i] + tag[in[i]] >= num) ans ++;
}
for(int i=in[l]+; i<in[r]; i++)
ans += check(i, num);
return ans;
}
BLOCK () {
read(N), read(Q);
build();
char opt;
int l, r, num;
for(int i=; i<=Q; i++) {
cin>>opt;
read(l), read(r), read(num);
if(opt == 'M') update(l, r, num);
else printf("%d\n", query(l, r, num));
}
}
}BLO;
int main() {}
「 Luogu P2801 」 教主的魔法——分块的更多相关文章
- 「BZOJ3343」教主的魔法(分块+二分查找)
题意: 给定一个数列,您需要支持以下两种操作:给[l,r]同加一个数询问[l,r]中有多少数字大于或等于v (n<=1000000,m<=3000) 题解 块内排序二分查询修改就用个数组存 ...
- Luogu 2801 教主的魔法 | 分块模板题
Luogu 2801 教主的魔法 | 分块模板题 我犯的错误: 有一处l打成了1,还看不出来-- 缩小块大小De完bug后忘了把块大小改回去就提交--还以为自己一定能A了-- #include < ...
- BZOJ 3343: 教主的魔法(分块+二分查找)
BZOJ 3343: 教主的魔法(分块+二分查找) 3343: 教主的魔法 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1172 Solved: ...
- 洛谷P2801 教主的魔法 [分块,二分答案]
题目传送门 教主的魔法 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. ...
- 题解 P2801 【教主的魔法】
分块入门题,不错的,建议大家做一做 开始学习 先看一下数列分块入门 2 这道题想让我们求区间[l,r]>=c的个数,然后我们可以看到"数列分块入门 2"是求区间[l,r]&l ...
- BZOJ 3343: 教主的魔法 [分块]【学习笔记】
3343: 教主的魔法 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1172 Solved: 526[Submit][Status][Discus ...
- 【BZOJ-3343】教主的魔法 分块
3343: 教主的魔法 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 950 Solved: 414[Submit][Status][Discuss ...
- 【BZOJ3343】教主的魔法 分块+二分
Description 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的 ...
- BZOJ3343: 教主的魔法 分块
2016-05-28 10:27:19 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3343 比较显然的分块题,分块后块内排序,维护整块的附 ...
随机推荐
- E20170426-gg
recursive adj. 回归的,递归的; removal n. 除去; 搬迁; 免职; 移走; customize vt. 定制,定做; 按规格改制;
- poj2389 普通的大数乘法
= =.每次这种题目说只有40位 然而要开到100位,心里总是一万匹草泥马在奔腾: #include <iostream> #include <stdio.h> #includ ...
- 洛谷P2585 [ZJOI2006]三色二叉树(树形dp)
传送门 设$dp[u][i]$表示点$u$颜色为$i$时最多(最少)的绿点个数(这里用$0$表示绿点) 然后直接用树形dp就可以了 记得把情况讨论清楚 //minamoto #include<b ...
- vue父组件调用子组件方法
父组件: 代码 <sampleapplylinemodel ref="sampleapplylinemodel" @reLoad="_fetchRecords&qu ...
- git 项目切换分支 命令
在项目开发总,一般都会用到git管理工具,有的公司可能还是用的svn:不管怎么样.用的顺手就行: 来说下git 的基本使用 git clone + 项目地址链接: 可以把项目克隆到本地: 然后一般顺序 ...
- 分布式集群环境下,如何实现session共享四(部署项目测试)
这是分布式集群环境下,如何实现session共享系列的第四篇.在上一篇:分布式集群环境下,如何实现session共享三(环境搭建)中,已经准备好了相关的环境:tomcat.nginx.redis.本篇 ...
- hdu3938 Portal 离线+并查集
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int ...
- python中的栈
# @File: stack # 列表实现栈 class MyStack(object): def __init__(self): self.data = [] def push(self, item ...
- Linux常用命令——tac、bc
1.从文件尾到文件头一页一页的显示内容 tac xxx.log |more //tac命令与cat命令相反,从文件尾开始读文件 2.shell下科学计算工具bc echo "scale=5; ...
- python工具之日志记录
''' 写日志类 日志存放目录为当前应用程序的目录下的log目录中 日志产生规则:每小时产生一个文件 write by :wujf 2017-02-24 ''' import sys import o ...