版权声明:如果路过的各位大佬想对菜鸡进行指点请加QQ:3360769137 https://blog.csdn.net/PleasantlY1/article/details/84204078
例题:
给定一个序列,有多次询问,每次查询区间里小于等于某个数的元素的个数
即对于询问 (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;
}//预处理,树状数组区间和加速
主席树板子:
暂缺