题解 数数

题目链接

可持久化平衡树看上去很行的样子,但是我不会啊。。。

先来考虑一个简化版的问题:求区间 [1,n]Hi 的元素个数。

这显然是好做的,用权值树状数组就行。

回到本题,显然:询问区间 [l,r]Hi 的个数,等价与区间 [1,r] 的答案减去区间 [1,l1] 的答案。所以,我们将一个询问拆成上述形式的两个询问,并且附上一个 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;
}
posted @   2017BeiJiang  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示