• [洛谷P2801]教主的魔法


    题目传送门

    一道分块的好题。

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

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

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

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

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

    第一个复杂度为$O(sqrt{n})$,第二个为$O(sqrt{n}log sqrt{n})$。总的为$O(Qsqrt{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
    ", Query(L, R, W));
    78         else if (c == 'M') Update(L, R, W);
    79     }
    80     return 0;
    81 }

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

  • 相关阅读:
    UVA-448
    算法提高-集合选取
    算法训练Maze
    UVA-10061
    树状数组
    前缀和
    【UVA
    统计Linux下的CPU状态信息
    Android_内部文件读取
    Android打开/data/目录以及导出文件
  • 原文地址:https://www.cnblogs.com/ac-evil/p/10348570.html
Copyright © 2020-2023  润新知