BZOJ3343

来源:互联网 发布:热传导有限元软件 编辑:程序博客网 时间:2024/04/28 18:23

3343: 教主的魔法

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1038  Solved: 454
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

2
3

HINT

【输入输出样例说明】

原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。

 

【数据范围】

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

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

Source

[Submit][Status][Discuss]


分块是门大学问,,GG
对于每个块,维护其块内数字有序
每个修改操作,中间的块打上标记,两边的块暴力修改+块重建
每个询问操作,中间的块二分答案,两边的块暴力找
O(Q根号nlog根号n)
#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int MAXN = 1000005;const int MAXM = 1005;char c[5];int a[MAXN], i, j, n, k, m, block[MAXM][MAXM], cnt[MAXM], x, y, w, ans;inline int get(){char c;while ((c = getchar()) < 48 || c > 57);int res = c - 48;while ((c = getchar()) >= 48 && c <= 57)res = res * 10 + c - 48;return res;}int main(){cin >> n >> m;for(i = 1; i <= n; i ++)a[i] = get();int nn = sqrt(n);nn += (n % nn != 0);for(i = 1; i <= nn; i ++){for(j = (i - 1) * nn + 1, k = 1; j <= i * nn; j ++, k ++)block[i][k] = a[j];sort(block[i] + 1, block[i] + nn + 1);}for(i = 1; i <= m; i ++){scanf("%s", c);x = get(); y = get(); w = get();if (x > y) swap(x, y);int bx = x / nn + (x % nn != 0);int by = y / nn + (y % nn != 0);if (c[0] == 'M'){if (bx == by){for(j = x; j <= y; j ++)a[j] += w;k = 1;for(j = (bx - 1) * nn + 1; j <= bx * nn; j ++, k ++)block[bx][k] = a[j];sort(block[bx] + 1, block[bx] + 1 + nn);continue;}if (bx < by - 1){for(j = bx + 1; j <= by - 1; j ++)cnt[j] += w;}for(j = x; j <= bx * nn; j ++)a[j] += w;for(j = nn * (by - 1) + 1; j <= y; j ++)a[j] += w;k = 1;for(j = (bx - 1) * nn + 1; j <= nn * bx; j ++, k ++)block[bx][k] = a[j];k = 1;for(j = (by - 1) * nn + 1; j <= nn * by; j ++, k ++)block[by][k] = a[j];sort(block[bx] + 1, block[bx] + 1 + nn);sort(block[by] + 1, block[by] + 1 + nn);}else{ans = 0;if (bx == by){for(j = x; j <= y; j ++)ans += (a[j] + cnt[bx] >= w);printf("%d\n", ans);continue;}if (bx < by - 1){for(j = bx + 1; j <= by - 1; j ++){int c = w - cnt[j];int l = 1, r = nn;while (l != r - 1){if (l == r) break;int mid = (l + r) >> 1;if (block[j][mid] >= c) r = mid;else l = mid;  }if (block[j][l] >= c) ans += nn - l + 1;else if (block[j][r] >= c) ans += nn - r + 1;}}for(j = x; j <= bx * nn; j ++)ans += (a[j] + cnt[bx] >= w);for(j = (by - 1) * nn + 1; j <= y; j ++)ans += (a[j] + cnt[by] >= w);printf("%d\n", ans);}}}

0 0