[洛谷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 }
当然还有更优的做法。这里就不放了。
标签:Right,洛谷,int,P2801,魔法,Tot,Size,rep,Left 来源: https://www.cnblogs.com/ac-evil/p/10348570.html