P10814 【模板】离线二维数点题解

题目背景

青蛙。

题目描述

给你一个长为 n 的序列 a,有 m 次询问,每次询问给定 l,r,x,求 [l,r] 区间中小于等于 x 的元素个数。

输入格式

第一行两个数 n,m。

第二行 n 个数表示序列 a。

之后 m 行,每行三个数 l,r,x 表示一次询问。

输出格式

对每个询问,输出一行一个数表示答案。

输入输出样例

输入 #1复制

6 4
1 1 4 5 1 4
1 6 3
1 6 4
1 1 4
1 5 4

输出 #1复制

3
5
1
4

说明/提示

对于 20% 的数据,满足 1≤n,m,ai​,l,r,x≤100。

对于 40% 的数据,满足 1≤n,m,ai​,l,r,x≤104。

对于 60% 的数据,满足 1≤n,m,ai​,l,r,x≤105。

对于 80% 的数据,满足 1≤n,m,ai​,l,r,x≤106。

对于 100% 的数据,满足 1≤n,m,ai​,l,r,x≤2×106。

思路

离线操作,树状数组维护。

代码见下

#include<bits/stdc++.h>
using namespace std;
int n,m,b[2000006],a2[2000006],a3[2000006],u,x,y;
struct one{
    int l,r,x,d,e;
}a[2000006];
bool cmp(one a1,one b1){
    return a1.r<b1.r;
}
bool cmp2(one a1,one b1){
    return a1.l<b1.l;
}
bool cmp3(one a1,one b1){
    return a1.e<b1.e;
}
int lb(int x){
    return x&(-x);
}
void ci(int x,int d){
    while(x<=n){
        a2[x]+=d;
        x+=lb(x);
    }
}
int co(int x){
    int lks=0;
    while(x>=1){
        lks+=a2[x];
        x-=lb(x);
    }
    return lks;
}
void ci2(int x,int d){
    while(x<=n){
        a3[x]+=d;
        x+=lb(x);
    }
}
int co2(int x){
    int lks=0;
    while(x>=1){
        lks+=a3[x];
        x-=lb(x);
    }
    return lks;
}
int main(){
	cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%ld",&b[i]);
    }
    for(int i=1;i<=m;i++){
        scanf("%ld%ld%ld",&a[i].l,&a[i].r,&a[i].x);
        a[i].e=i;
    }
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++){
        for(int j=a[i-1].r+1;j<=a[i].r;j++){
            ci(b[j],1);
        }
        a[i].d=co(a[i].x);
    }
    sort(a+1,a+m+1,cmp2);
    for(int i=1;i<=m;i++){
        for(int j=max(1,a[i-1].l);j<=a[i].l-1;j++){
            ci2(b[j],1);
        }
        a[i].d-=co2(a[i].x);
    }
    sort(a+1,a+m+1,cmp3);
    for(int i=1;i<=m;i++){
        cout<<a[i].d<<endl;
    }
    return 0;
}

posted @ 2025-10-11 07:54  bz02_2023f2  阅读(10)  评论(0)    收藏  举报  来源