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;
}

浙公网安备 33010602011771号