换个角度思考(牛客4.30 树状数组)

换个角度思考

题目链接

题目描述
给定一个序列,有多次询问,每次查询区间里小于等于某个数的元素的个数
即对于询问 ( l , r , x ) (l,r,x) (l,r,x) ,你需要输出 ∑ i = l r [ a i ≤ x ] \sum_{i=l}^{r}[a_i \le x] i=lr[aix] 的值
其中 [ e x p ] [exp] [exp] 是一个函数,它返回 1 当且仅当 exp 成立,其中 exp 表示某个表达式
输入描述:
第一行两个整数 n , m n,m n,m
第二行 n n n 个整数表示序列 a a a 的元素,序列下标从 1 开始标号,保证 1 ≤ a i ≤ 1 0 5 1 ≤ a_i ≤ 10^5 1ai105
之后有 m m m 行,每行三个整数 ( l , r , k ) (l,r,k) (l,r,k) ,保证 1 ≤ l ≤ r ≤ n 1 ≤ l ≤ r ≤ n 1lrn ,且 1 ≤ k ≤ 1 0 5 1 ≤ k ≤ 10^5 1k105
输出描述:
对于每一个询问,输出一个整数表示答案后回车
示例1
输入
5 1
1 2 3 4 5
1 5 3
输出
3
备注:
数据范围
1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105
1 ≤ m ≤ 1 0 5 1 \le m \le 10^5 1m105

思路:
可以离线查询,查询次序按照 x x x 从小到大排序,树状数组表示这个序列的 i i i 位置处有几个数字,每次查询前把所有 a i ≤ x a_i\le x aix 的数在它原来对应的位置 i i i + 1 +1 +1 ,然后查询结果就是前 r r r 部分减去前 l − 1 l-1 l1 部分。

Code:

#include 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
int n, m, c[N], ans[N];
pii a[N];
struct node
{
    int id, l, r, x;
} q[N];
bool cmp(const node &A, const node &B) { return A.x < B.x; }
int lowbit(int x) { return x & -x; }
void update(int pos)
{
    while (pos <= n)
    {
        c[pos]++;
        pos += lowbit(pos);
    }
}
int quary(int pos)
{
    int res = 0;
    while (pos > 0)
    {
        res += c[pos];
        pos -= lowbit(pos);
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    	cin >> a[i].first, a[i].second = i;
    for (int i = 1; i <= m; i++)
    	cin >> q[i].l >> q[i].r >> q[i].x, q[i].id = i;
    sort(a + 1, a + n + 1);
    sort(q + 1, q + m + 1, cmp);
    int p = 1;
    for (int i = 1; i <= m; i++)
    {
        while (a[p].first <= q[i].x && p <= n)
        {
            update(a[p].second);
            p++;
        }
        ans[q[i].id] = quary(q[i].r) - quary(q[i].l - 1);
    }
    for (int i = 1; i <= m; i++)
        cout << ans[i] << endl;
    return 0;
}

你可能感兴趣的:(树状数组,牛客练习)