區間查詢小於等於某數
阿新 • • 發佈:2019-01-04
例題:
給定一個序列,有多次詢問,每次查詢區間裡小於等於某個數的元素的個數
即對於詢問 (l,r,x),你需要輸出 的值
其中 [exp] 是一個函式,它返回 1 當且僅當 exp 成立,其中 exp 表示某個表示式
輸入描述:
第一行兩個整數n,m 第二行n個整數表示序列a的元素,序列下標從1開始標號,保證1 ≤ ai ≤ 105 之後有m行,每行三個整數(l,r,k),保證1 ≤ l ≤ r ≤ n,且1 ≤ k ≤ 105
輸出描述:
對於每一個詢問,輸出一個整數表示答案後回車
示例1
輸入
5 1 1 2 3 4 5 1 5 3
輸出
3
備註:
資料範圍 1 ≤ n ≤ 10^5 1 ≤ m ≤ 10^5
就是這一道題引出來的慘劇——大佬們花式過題,小白死扣模板。
這道題解法很多,因為資料問題這個題普通暴力也能過。
普通暴力:
#include <stdio.h> int arr[101000]; int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",arr+i); while(m--){ int l,r,x; int sum=0; scanf("%d%d%d",&l,&r,&x); for(int i=l;i<=r;i++) if(arr[i]<=x)sum++; printf("%d\n",sum); } }
分塊暴力:
線段樹+二分:
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> #define per(i,a,b) for(int i=a;i<=b;++i) using namespace std; const int maxn=100005; int n,m; int a[maxn]; vector<int>v[maxn<<2]; vector<int>::iterator it; void build(int id,int l,int r) { v[id].clear(); per(i,l,r) v[id].push_back(a[i]); sort(v[id].begin(),v[id].end()); if(l==r) return; int mid=(l+r)>>1; build(id<<1,l,mid); build(id<<1|1,mid+1,r); } int query(int id,int L,int R,int l,int r,int h) { if(l<=L&&R<=r) { it=upper_bound(v[id].begin(),v[id].end(),h); return it-v[id].begin(); } int mid=(L+R)>>1; int ans=0; if(l<=mid) ans+=query(id<<1,L,mid,l,r,h); if(mid<r) ans+=query(id<<1|1,mid+1,R,l,r,h); return ans; } int main() { int T,t=1; scanf("%d%d",&n,&m); per(i,1,n) scanf("%d",&a[i]); build(1,1,n); int l,r,h; while(m--) { scanf("%d%d%d",&l,&r,&h); printf("%d\n",query(1,1,n,l,r,h)); } return 0; }//線段樹+二分優化
樹狀陣列基礎運用:
#include<bits/stdc++.h>
#define per(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
int n,m,bit[100005],s[100005];
struct node{
int x,id;
}p[100005];
struct Node{
int l,r,x,id;
}q[100005];
int cmp1(node a,node b)
{
return a.x<b.x;
}
int cmp2(Node a,Node b)
{
return a.x<b.x;
}
inline int lowbit(int i)
{
return i&(-i);
}
void add(int i)
{
while(i<=n){
bit[i]++;i+=lowbit(i);
}
}
int sum(int i)
{
int res=0;
while(i>0){
res+=bit[i];i-=lowbit(i);
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
per(i,1,n)
{
scanf("%d",&p[i].x);
p[i].id=i;
}
sort(p+1,p+1+n,cmp1);//從小到大
per(i,1,m)
{
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].x);
q[i].id=i;
}
sort(q+1,q+1+m,cmp2);//對需操作進行排序 按k排序
int it=1;
per(i,1,m)
{
while(p[it].x<=q[i].x&&it<=n)//滿足大小條件
{
add(p[it].id);it++;//陣列存位置(add操作是對該位置以後的影響進行處理,對之前的吳操作)
}
s[q[i].id]=sum(q[i].r)-sum(q[i].l-1);//區間和
}
per(i,1,m) printf("%d\n",s[i]);
return 0;
}//預處理,樹狀陣列區間和加速
主席樹板子:
暫缺