牛客小白9 换个角度思考(离线+树状数组)


title: 牛客小白9 换个角度思考(离线+树状数组)
date: 2018-11-29 15:25:18
tags: [离线,树状数组]
categories: ACM

题目链接

题目描述

给定一个序列,有多次询问,每次查询区间里小于等于某个数的元素的个数
即对于询问 (l,r,x),你需要输出 img 的值
其中 [exp] 是一个函数,它返回 1 当且仅当 exp 成立,其中 exp 表示某个表达式

输入描述:

第一行两个整数n,m
第二行n个整数表示序列a的元素,序列下标从1开始标号,保证1 ≤ ai ≤ 105
之后有m行,每行三个整数(l,r,k),保证1 ≤ l ≤ r ≤ n,且1 ≤ k ≤ 105

输出描述:

对于每一个询问,输出一个整数表示答案后回车

输入

5 1
1 2 3 4 5
1 5 3

输出

3

备注:

数据范围
1 ≤ n ≤ 105
1 ≤ m ≤ 105

思路

  • 将原数组和要查询的K值升序排列,这样能保证前面小的数的贡献对后面也有影响
  • 然后用树状数组维护
#include <bits/stdc++.h>
#define N 100006
#define mem(a, b) memset(a, b, sizeof(a))
#define LL  long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
using namespace std;

struct ac{
    int val, id, l, r;
}a[N], b[N];
int ans[N], c[N];
int n, m;

void update(int x, int d) {
    while (x <= n) {
        c[x] += d;
        x += lowbit(x);
    }
}

int query(int x) {
    int ans = 0;
    while (x) {
        ans += c[x];
        x -= lowbit(x);
    }
    return ans;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    scanf("%d %d", &n, &m);

    // 读入数组,并记录序号
    for (int i = 0; i < n; ++i) {
        scanf("%d", &a[i].val);
        a[i].id = i + 1;
    }

    // 读入查询,记录序号
    for (int i = 0; i < m; ++i) {
        scanf("%d %d %d", &b[i].l, &b[i].r, &b[i].val);
        b[i].id = i + 1;
    }

    // 分别升序排列
    sort(a, a + n, [&](const ac &x, const ac &y){
        return x.val < y.val;
    });
    sort(b, b + m, [&](const ac &x, const ac &y){
        return x.val < y.val;
    });

    // j枚举原数组 1-n 的数字
    int j = 0;
    for (int i = 0; i < m; ++i) {
        // 存在小于当前查询的K值,就树状数组更新贡献
        while (j < n && a[j].val <= b[i].val) {
            update(a[j].id, 1);
            ++j;
        }
        // 将答案按照序号保存在数组中
        ans[b[i].id] = query(b[i].r) - query(b[i].l - 1);
    }
    for (int i = 1; i <= m; ++i) {
        printf("%d\n", ans[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/84633854