分块+二分 BZOJ 3343

3343: 教主的魔法

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1312  Solved: 585
[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]

 

 

思路:

分块以后,对于每个询问区间[L,R],对于收尾两个区间进行暴力寻找即可。对于中间的块,我们提前进行排序然后进行二分寻找大于c-add[now_block_id]即可(因为每个块是sqrt(n)个元素,所以总的复杂度应该是n*sqrt(n)*log(n))

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 1000000 + 5;
int n, q;
int block, num, belong[maxn], L[maxn], R[maxn];
int add[maxn], a[maxn], d[maxn];

void build_block(){
    block = sqrt(n * 1.0); num = n / block;
    if (n % block) num++;
    for (int i = 1; i <= num; i++){
        L[i] = (i - 1) * block + 1, R[i] = i * block;
    }
    R[num] = n;
    for (int i = 1; i <= n; i++)
        belong[i] = (i - 1) / block + 1;
    for (int i = 1; i <= num; i++){
        sort(d + L[i], d + R[i] + 1);
    }
}

void modify(int l, int r){
    for (int i = l; i <= r; i++)
        d[i] = a[i];
    sort(d + l, d + r + 1);
}

void update(int ql, int qr, int w){
    if (belong[ql] == belong[qr]){
        for (int i = ql; i <= qr; i++)
            a[i] += w;
        modify(L[belong[ql]], R[belong[ql]]);
        return ;
    }
    for (int i = ql; i <= R[belong[ql]]; i++)
        a[i] += w;
    modify(L[belong[ql]], R[belong[ql]]);

    for (int i = L[belong[qr]]; i <= qr; i++)
        a[i] += w;
    modify(L[belong[qr]], R[belong[qr]]);

    for (int i = belong[ql] + 1; i < belong[qr]; i++)
        add[i] += w;
}

int query(int ql, int qr, int c){
    int ans = 0;
    if (belong[ql] == belong[qr]){
        for (int i = ql; i <= qr; i++)
            if (c - add[belong[ql]] <= a[i]) ans++;
        return ans;
    }
    for (int i = ql; i <= R[belong[ql]]; i++)
        if (c - add[belong[ql]] <= a[i]) ans++;

    for (int i = L[belong[qr]]; i <= qr; i++)
        if (c - add[belong[qr]] <= a[i]) ans++;
    for (int i = belong[ql] + 1; i < belong[qr]; i++){
        int l = L[i], r = R[i];
        int p = lower_bound(d + l, d + r + 1, c - add[i]) - d;
        ans += r + 1 - p;
    }
    return ans;
}

int main(){
    cin >> n >> q;
    for (int i = 1; i <= n; i++){
        scanf("%d", a + i);
        d[i] = a[i];
    }
    build_block();
    while (q--){
        char ch[2]; int a, b, c;
        scanf("%s%d%d%d", ch, &a, &b, &c);
        if (ch[0] == 'A'){
            printf("%d\n", query(a, b, c));
        }
        else update(a, b, c);
    }
    return 0;
}
View Code

 

posted @ 2017-03-04 15:33  知る奇迹に  阅读(108)  评论(0编辑  收藏