[洛谷P2801]教主的魔法

题目传送门

一道分块的好题。

这题分块后,对于两种操作:

·让区间[l,r]+=w;

·查询区间[l,r]>=c的数的个数

分块后,我们将每一块中的数排序,这样每一块中的查询可以通过二分完成。

对于区间的修改,如果覆盖了整块,通过标签的修改满足题意;如果只是块中的一部分,暴力修改原数组再重新排序维护。

第一个复杂度为$O(\sqrt{n})$,第二个为$O(\sqrt{n}log \sqrt{n})$。总的为$O(Q\sqrt{n}log \sqrt{n})$

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define maxx(a, b) a = max(a, b);
 9 #define minn(a, b) a = min(a, b);
10 #define LL long long
11 #define inf (1 << 30)
12 
13 inline int read() {
14     int w = 0, f = 1; char c = getchar();
15     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
16     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
17     return w * f;
18 }
19 
20 const int maxn = 1e6 + 5, Size = 1000;
21 
22 int A[maxn], B[maxn], N, Q, tag[maxn];
23 
24 #define pos(x) ((x+Size-1)/Size)
25 
26 void Build(int P) {
27     rep(i, (P-1)*Size+1, P*Size) B[i] = A[i];
28     sort(B + (P-1)*Size + 1, B + P*Size + 1);
29 }
30 
31 void Update(int L, int R, int W) {
32     int Left = pos(L)+1, Right = pos(R)-1;
33     rep(i, Left, Right) tag[i] += W;
34     if (Left-1 > Right) {
35         rep(i, L, R) A[i] += W;
36         Build(Left-1);
37     } else {
38         rep(i, L, (Left-1)*Size) A[i] += W;
39         rep(i, Right*Size+1, R) A[i] += W;
40         Build(Left-1), Build(Right+1);
41     }
42 }
43 
44 int find(int P, int v) {
45     register int L = (P-1)*Size+1, R = P*Size, Mid, Ans = R+1;
46     while (L <= R) {
47         Mid = (L + R) >> 1;
48         if (B[Mid] >= v) R = Mid-1, Ans = Mid;
49         else L = Mid+1;
50     }
51     return P*Size-Ans+1;
52 }
53 
54 int Query(int L, int R, int C) {
55     int Left = pos(L)+1, Right = pos(R)-1, Tot = 0;
56     rep(i, Left, Right) Tot += find(i, C-tag[i]);
57     if (Left-1 > Right) {
58         rep(i, L, R) if (A[i] >= C-tag[Left-1]) Tot++;
59     } else {
60         rep(i, L, (Left-1)*Size) if (A[i] >= C-tag[Left-1]) Tot++;
61         rep(i, Right*Size+1, R) if (A[i] >= C-tag[Right+1]) Tot++;
62     }
63     return Tot;
64 }
65 
66 int main() {
67     N = read(), Q = read();
68     rep(i, 1, N) B[i] = A[i] = read();
69 
70     for (register int i = 1; i <= N; i += Size) sort(B + i, B + min(N+1, Size + i));
71     memset(tag, 0, sizeof(tag));
72 
73     rep(i, 1, Q) {
74         char c = getchar();
75         while (c != 'A' && c != 'M') c = getchar();
76         int L = read(), R = read(), W = read();
77         if (c == 'A') printf("%d\n", Query(L, R, W));
78         else if (c == 'M') Update(L, R, W);
79     }
80     return 0;
81 }

当然还有更优的做法。这里就不放了。

posted @ 2019-02-02 15:44  AC-Evil  阅读(218)  评论(0编辑  收藏  举报