[Luogu] 教主的魔法

https://www.luogu.org/problemnew/show/P2801

分块

对于每一块进行排序存储在另一个数组中

二分查询

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;

#define gc getchar()

const int N = 1e6 + 10;
const int M = 1e3 + 10;

int A[N], B[N], Pos[N], Add[M];
int n, Q, cnt, block;

inline int read(){
    int x = 0, f = 1; char c = gc;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = gc;}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
    return x * f;
}

inline void Sort(int x){
    int l = (x - 1) * block + 1, r = min(n, x * block);
    for(int i = l; i <= r; i ++) B[i] = A[i];
    sort(B + l, B + r + 1);
} 

inline void Sec_G(int x, int y, int z){
    if(Pos[x] == Pos[y]){for(int i = x; i <= y; i ++) A[i] += z; Sort(Pos[x]); return ;}
    else {
        for(int i = x; i <= Pos[x] * block; i ++) A[i] += z;
        for(int i = (Pos[y] - 1) * block + 1; i <= y; i ++) A[i] += z;
        Sort(Pos[x]); Sort(Pos[y]);
    }
    for(int i = Pos[x] + 1; i < Pos[y]; i ++) Add[i] += z;
}

inline int to_calc(int x, int num){
    int l = (x - 1) * block, r = min(x * block, n), last = r, ans;
    while(l <= r){
        int mid = (l + r) >> 1;
        if(B[mid] < num) ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    return last - ans + 1;
}

inline int Sec_A(int x, int y, int z){
    int answer(0);
    if(Pos[x] == Pos[y]){for(int i = x; i <= y; i ++) if(A[i] + Add[Pos[x]] >= z) answer ++; return answer;}
    else {
        for(int i = x; i <= Pos[x] * block; i ++) if(A[i] + Add[Pos[x]] >= z) answer ++;
        for(int i = (Pos[y] - 1) * block + 1; i <= y; i ++) if(A[i] + Add[Pos[y]] >= z) answer ++;
    }
    for(int i = Pos[x] + 1; i < Pos[y]; i ++) answer += to_calc(i, z - Add[i]);
    return answer;
} 

int main()
{
    freopen("gg.in", "r", stdin);
    n = read(); Q = read();
    block = sqrt(n);
    for(int i = 1; i <= n; i ++) A[i] = read();
    for(int i = 1; i <= n; i ++) Pos[i] = (i - 1) / block + 1;
    for(int i = 1; i <= n; i ++) Sort(i);
    if(n % block) cnt = n / block + 1;
    else cnt = n / block;
    while(Q --){
        string s; cin >> s;
        int x = read(), y = read(), z = read();
        if(s[0] == 'A') Sec_G(x, y, z);
        else cout << Sec_A(x, y, z) << endl;
    }
    
    return 0;
}
/*
5 3
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4
*/

 

posted @ 2017-12-26 21:48  xayata  阅读(143)  评论(0编辑  收藏  举报