HDU 4417 Super Mario (树状数组)

思路:

  1. 首先我们先回顾一下树状数组。树状数组的的直接目的即区间求和(logn)。但由于具有logn单点修改的功能使得区间求和更为方便。
  2. 对于这道题来说,我们先对m个询问中的h升序排序,利用了<=h1的元素一定也<=h2这个递推式,然后将n个数也排序,但同时需要记录这些数原本的位置信息。
  3. 对于每个询问,我们将符合hi条件的点加入树状数组,注意,我们是将这个点原来的位置加入树状数组(数量是1)。这样构造出来的数组即是满足当前所有点<=hi的情况下,getsum_tree[i]得到的即是小于等于位置i的满足条件的点的个数。
  4. 对于某个区间i,j来说,getsum_tree[j] - getsum_tree[i]。注意根据实际情况讨论边界。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;

int n,m;
int c[100010];

struct san{
    int val,p;
    san(){}
    san(int vv,int i){val = vv,p = i;}
}lisan[100010];

struct node1{
    int l,r,h,num;
    node1(){}
    node1(int ll,int rr,int hh,int numm){
        l = ll,r = rr, h = hh, num = numm;
    }
}query[100010];

void insert(int i,int x){
    while(i <= n){
        c[i] += x;
        i += (i&-i);
    }
}
int getsum(int i){
    int sum = 0;
    while(i > 0){
        sum += c[i];
        i -= (i&-i);
    }
    return sum;
}

int ans[100010];

bool cmp(const san&a, const san&b){return a.val<b.val;}
bool cmp2(const node1&a, const node1&b){return a.h<b.h;}

int main(){
    int t;
    cin>>t;
    int nca = 0;
    while(t--){
        memset(c,0,sizeof(c));
        memset(lisan,0,sizeof(lisan));
        nca++;
        scanf("%d%d",&n,&m);
        int temp;
        for(int i = 1;i <= n;i++){
            scanf("%d",&temp);
            lisan[i] = san(temp,i);
        }
        for(int i = 1;i <= m;i++){
            scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].h);
            query[i].num = i;
        }
        sort(lisan+1,lisan+1+n,cmp);
        sort(query+1,query+1+m,cmp2);

        int now = 1;
        for(int i = 1;i <= n;i++){
            if(lisan[i].val <= query[now].h){
                insert(lisan[i].p,1);
            }
            else if(now <= m-1){
                ans[query[now].num] = getsum(query[now].r+1) - getsum(query[now].l) ;
                now++;
                i--;
            }
            else break;
        }
        for(int i = now;i <= m;i++){
            ans[query[i].num] = getsum(query[i].r+1) - getsum(query[i].l);
        }
        printf("Case %d:\n",nca);
        for(int i = 1;i <= m;i++){
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值