hdu4417Super Mario 树状数组+二分

//给出n个数ai
//m次询问l , r ,h
//问区间[l,r]中小于h的数的个数
//先离线,记录每次询问的区间的位置
//然后可以用树状数组知道在为位置i小于h的数的个数
//答案就是右边的个数减去左边的个数
//ai和h很大,所以用二分记录数找位置
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
using namespace std ;
const int maxn = 1e5+10 ;
int a[maxn] ;
int b[maxn] ;
int tree[maxn] ;
vector<pair<int,int> >l[maxn] , r[maxn] ;
int ans[maxn] ;
void update(int x , int dx)
{
    while(x < maxn)
    {
        tree[x] += dx ;
        x += x&(-x) ;
    }
}
int getsum(int x)
{
    int sum = 0 ;
    while(x)
    {
        sum += tree[x]  ;
        x -= x&(-x) ;
    }
    return sum ;
}
int main()
{
    int t ;
    scanf("%d" , &t) ;
    int cas = 0 ;
    while(t--)
    {
        memset(tree , 0 , sizeof(tree)) ;
        memset(ans , 0 , sizeof(ans)) ;
        int n , m ;
        scanf("%d%d" , &n , &m) ;
        for(int i = 1;i <= n;i++)
        scanf("%d" , &a[i]) , b[i] = a[i] ,l[i].clear() , r[i].clear() ;
        sort(a+1 , a+1+n) ;
        int len = unique(a+1 , a+1+n) - (a+1) ;
        for(int i = 1;i <= m;i++)
        {
            int x , y , h ;
            scanf("%d%d%d" , &x , &y , &h) ;
            int pos = upper_bound(a+1 , a+1+len , h) - (a+1) ;
            if(pos)
            {
                l[x].push_back(make_pair(pos, i)) ;
                r[y+1].push_back(make_pair(pos, i)) ;
            }
        }
        for(int i = 1;i <= n;i++)
        {
            int pos = lower_bound(a+1 , a+1+len , b[i]) - a ;
            update(pos , 1) ;
            for(int j = 0;j < l[i].size();j++)
            ans[l[i][j].second] -= getsum(l[i][j].first) ;
            for(int j = 0;j < r[i].size();j++)
            ans[r[i][j].second] += getsum(r[i][j].first) ;
        }
        printf("Case %d:\n" , ++cas) ;
        for(int i = 1;i <= m;i++)
        printf("%d\n" , ans[i]) ;
    }
    return  0 ;
}

你可能感兴趣的:(hdu4417Super Mario 树状数组+二分)