题解 数数

题目链接

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

先来考虑一个简化版的问题:求区间 \([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;
}
posted @ 2023-08-24 14:37  2017BeiJiang  阅读(5)  评论(0编辑  收藏  举报