HDU 4417(主席树模版题,求区间值 小于等于 k 的个数)

题目链接:芝麻开门

题意:给定一个数组,每一次询问 区间 [L,R] 中   值  <= h 的个数。

思路:开始一直wa,由于自己的query 是用的非递归,考虑掉了 L == R 需要特判的情况。

build 以及 update 和 静态主席树无异。查询的时候,如果 X[mid] <= h,ans += 左子树的所有值,然后查询右子树,否则继续查询左子树。最后再特判 L == R 的情况。

 

AC代码:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs i << 1 + 1
#define INT(t) int t; scanf("%d",&t)

using namespace std;

const int maxn = 1e5 + 10;
const int M = maxn * 40;
int K[maxn],X[maxn],T[maxn];
int C[M],lson[M],rson[M];
int tot,en;

int build(int l,int r){
    int rt = tot ++;
    C[rt] = 0;
    if(l != r){
        int mid = (l + r) >> 1;
        lson[rt] = build(l,mid);
        rson[rt] = build(mid + 1,r);
    }
    return rt;
}

int getId(int x){
    return lower_bound(X + 1,X + 1 + en,x) - X;
}

int udt(int rt,int pos,int val){
    int newrt = tot ++, tmp = newrt;
    C[newrt] = C[rt] + val;
    int l = 1,r = en;
    while(l < r){
        int mid = (l + r) >> 1;
        if(pos <= mid){
            lson[newrt] = tot ++;
            rson[newrt] = rson[rt];
            newrt = lson[newrt];
            rt = lson[rt];
            r = mid;
        }
        else {
            rson[newrt] = tot ++;
            lson[newrt] = lson[rt];
            newrt = rson[newrt];
            rt = rson[rt];
            l = mid + 1;
        }
        C[newrt] = C[rt] + val;
    }
    return tmp;
}

int query(int ql,int qr,int k){
    int lrt = T[ql - 1];
    int rrt = T[qr];
    int l = 1,r = en,ans = 0;
    while(l < r){
        int mid = (l + r) >> 1;
        if(X[mid] <= k){
            ans += C[lson[rrt]] - C[lson[lrt]];
            lrt = rson[lrt];
            rrt = rson[rrt];
            l = mid + 1;
        }
        else {  /// X[mid] > k
            lrt = lson[lrt];
            rrt = lson[rrt];
            r = mid;
        }
    }
    /// if(l == r) 是我的wa点
    if(l == r){
        if(X[l] <= k)
            ans += C[rrt] - C[lrt];
    }
    return ans;
}

int main() {
    int t; scanf("%d",&t);
    int cas = 0;
    while(t --){
        tot = 0;
        int n,m; scanf("%d%d",&n,&m);
        for(int i = 1;i <= n;++ i){
            scanf("%d",&K[i]);
            X[i] = K[i];
        }
        sort(X + 1,X + 1 + n);
        en = unique(X + 1,X + 1 + n) - X - 1;
        T[0] = build(1,en);
        for(int i = 1;i <= n;++ i)
            T[i] = udt(T[i - 1],getId(K[i]),1);
        printf("Case %d:\n",++ cas);
        while(m --){
            int l,r,k; scanf("%d%d%d",&l,&r,&k);
            printf("%d\n",query(l + 1,r + 1,k));
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值