@[toc]
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld
题目描述
输入描述:
第一行两个整数n,m 第二行n个整数表示序列a的元素,序列下标从1开始标号,保证1 ≤ ai ≤ 10^5^
之后有m行,每行三个整数(l,r,k),保证1 ≤ l ≤ r ≤ n,且1 ≤ k ≤ 10^5^
输出描述:
对于每一个询问,输出一个整数表示答案后回车
示例1
输入
5 1 1 2 3 4 5 1 5 3
输出
3
备注:
数据范围
1 ≤ n ≤ 10^5^
1 ≤ m ≤ 10^5^
题解:
主席树,树状数组等都可以做
主席树做法:
简单提一句主席树
主席树的本体其实是线段树,也就是很多棵线段树,用以存一段数字区间出现次数,主席树经常用于求一个序列内的第 k 小
在这里,主席树就是提前预处理好每个点的权值线段树,查询时,可以直接用r时刻前缀小于x的数量减去l-1的数量,剩下的就是[l,r]区间值
也就是[L,R]=[1,R]-[1,L-1],查询后两者相减即可
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+2; int n,m; int a[maxn]; vector<int>edge[maxn*4]; void build(int id,int l,int r) { edge[id].clear(); for(int i=l;i<=r;i++) edge[id].push_back(a[i]); sort(edge[id].begin(),edge[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 k) { int sum=0; vector<int>::iterator it; if(l<=L&&R<=r) { it=upper_bound(edge[id].begin(),edge[id].end(),k);//二分查找,第一个大于k的数,返回地址 return it-edge[id].begin();//两者做差的个数 } int mid=(L+R)/2; if(l<=mid) { sum+=query(id*2,L,mid,l,r,k); } if(mid<r) { sum+=query(id*2,mid+1,R,l,r,k); } return sum; } int main() { int l,r,k; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) cin>>a[i]; build(1,1,n); while(m--) { cin>>l>>r>>k; printf("%d\n",query(1,1,n,l,r,k)); } return 0; }
代码:
树状数组:
首先需要离线操作,我们每次查询都是要知道左右区间以及x,相当于同时有两个东西未知需要操作。通过离散后,我们可以控制其中一部分,另外一部分未知变化,例如:第一种我们查询[l,r]内有多少数满足条件,我们就要保证所有数都小于x;第二种如何问有多少数小于等于x,就保证范围取定于[l,r]。这样更高效,当然占空间更多。
简单的说:
离线操作:读入所有的操作数据,然后一次性处理。
在线操作:每读入一个操作数据,就进行一次操作。
第一种:
我们在保证所有数都是小于等于x的情况下来查询[l,r]有多少个数
每次询问[l,r,x]之前,把小于等于x的ai都加入加入到一个另外的位置上,这样里面存放的都是满足条件的数,直接询问即可
第二种:
保证所有数都在[l,r]区间的情况下,查询小于等于x的数量
我们可以在离线时,将[l,r]区间问题转化成 [ 1 , l-1 ] , [ 1 , r ] 两个区间,这样就可以用树状数组来解决
(这是邓老师的讲解,我加入自己的理解写出来的)
代码写完再更
更扯淡的方法!!!
这题貌似优化暴力就能过。。。
就是直接模拟,不知为啥过了。。快读都还没用上
#include <bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; const int N = 1e5 + 3; int a[N]; int main() { int n,m; cin>>n>>m; for (int i = 1; i <= n; ++i) cin>>a[i]; while (m--) { int l,r,k; cin>>l>>r>>k; int sum = 0; for (int i = l; i <= r; ++i) if (a[i] <= k) ++sum; printf("%d\n", sum); } return 0; }