题解 数数
可持久化平衡树看上去很行的样子,但是我不会啊。。。
先来考虑一个简化版的问题:求区间 \([1,n]\) 中 \(\le H_i\) 的元素个数。
这显然是好做的,用权值树状数组就行。
回到本题,显然:询问区间 \([l,r]\) 中 \(\le H_i\) 的个数,等价与区间 \([1,r]\) 的答案减去区间 \([1,l-1]\) 的答案。所以,我们将一个询问拆成上述形式的两个询问,并且附上一个 \(k\),表示这个询问对答案是加还是减,如果是加,就赋值位 \(1\),减则赋值为 \(-1\)。即:
struct node {
int r,id,k,h;
//分别表示,右边界,第几个问题,加还是减,h的值
};
然后按照右边界排序,依次做权值树状数组即可。
由于 \(h,a\) 的范围很大,所以先要离散化。
完整代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int T,n,q,m;
int a[N],b[N];
int ans[N];
int tr[N];
struct node {
int k,r,h,id;
};
vector<node> que;
int cmp(node x,node y) {
return x.r<y.r;
}
int find(int x) {
return lower_bound(b+1,b+1+m,x)-b;
}
int lowbit(int x) {
return x&(-x);
}
void modify(int nd,int x) {
for(int i=nd;i<=m;i+=lowbit(i)) tr[i]+=x;
}
int query(int nd) {
int ans=0;
for(int i=nd;i;i-=lowbit(i)) ans+=tr[i];
return ans;
}
void Solve() {
cin>>n>>q;
for(int i=1;i<=n;i++) {
cin>>a[i];
b[++m]=a[i];
}
for(int i=1;i<=q;i++) {
int l,r,h; cin>>l>>r>>h;
b[++m]=h;
que.push_back({1,r,h,i});
que.push_back({-1,l-1,h,i});
}
sort(b+1,b+1+m);
m=unique(b+1,b+1+m)-b-1;
sort(que.begin(),que.end(),cmp);
int nd=0;
for(auto t:que) {
while(nd+1<=t.r) {modify(find(a[nd+1]),1); nd++;}
ans[t.id]+=t.k*query(find(t.h));
}
for(int i=1;i<=q;i++) cout<<ans[i]<<' ';
cout<<endl;
}
void Clear() {
for(int i=1;i<=m;i++) b[i]=0;
for(int i=1;i<=n;i++) a[i]=0;
for(int i=1;i<=m;i++) tr[i]=0;
for(int i=1;i<=q;i++) ans[i]=0;
n=m=q=0;
que.clear();
}
int main() {
cin>>T;
while(T--) {
Solve();
Clear();
}
return 0;
}