【代码源每日一题Div1】数数「离线 + 树状数组」

数数

题目描述:

给定长度为n的数组a[i],进行Q次询问,每次询问都查询[L, R]中小于等于H的元素的个数

思路:

比较显然的离线+树状数组题目

我们可以将所有询问按照H从小到大排序,把数组a[i]也按照从小到大的顺序进行排序,同时记录原位置的下标

对于每次询问[l, r, h]我们将小于等于h的所有a[i]插到树状数组里面,插的是他在原数组的位置

输出的时候我们查询树状数组的r减去l-1的答案就行

#include <bits/stdc++.h>
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
typedef pair <int,int> pii;
#define lowbit(x) (x&(-x))
#define MAX 300000 + 50
int n, m, k, x;
pii fuck[MAX];
struct ran{
    
    
    int l, r, c, id;
    bool operator < (const ran &x)const{
    
    
        return c < x.c;
    }
}ar[MAX];
int ans[MAX];
int tr[MAX];
void add(int id){
    
    
    while(id <= n){
    
    
        ++tr[id];
        id += lowbit(id);
    }
}
int getans(int id){
    
    
    int ans = 0;
    while(id){
    
    
        ans += tr[id];
        id -= lowbit(id);
    }
    return ans;
}

void work(){
    
    
    cin >> n >> m;
    for(int i = 0; i <= 2*n; ++i)tr[i] = 0;
    for(int i = 1; i <= n; ++i){
    
    
        cin >> fuck[i].first;
        fuck[i].second = i;
    }
    sort(fuck + 1, fuck + 1 + n);
    for(int i = 1; i <= m; ++i){
    
    
        cin >> ar[i].l >> ar[i].r >> ar[i].c;
        ar[i].id = i;
    }
    sort(ar + 1, ar + 1 + m);
    int id = 0;
    for(int i = 1; i <= m; ++i){
    
    
        while(id+1<=n && fuck[id+1].first <= ar[i].c){
    
    
            ++id;
            add(fuck[id].second);
        }
        ans[ar[i].id] = getans(ar[i].r) - getans(ar[i].l - 1);
    }
    for(int i = 1; i <= m; ++i)cout << ans[i] << ' ';
    cout << endl;
}


int main(){
    
    
    io;
    int t;cin>>t;while(t--)
    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_51216553/article/details/127761513