[Hdu] 4417 Super Mario (主席树模板题)

地址链接:Hdu 4417

这道题应该是显然的模板题,区间求比K小的数的个数。当然由于数据的关系离散是必要的(虽然我对二分操作一直都很迷)。就借这道题稍微给自己的主席树模版介绍一下顺便贮存一下板子。

主席树只要理解了,写起来应该是挺容易的。它关键在于每个点更新的时候“新建”一个树,但新建的这个树,只有在发生改变的那logn个点新建,其它的点可以直接引用上一次的。这样每次新建只多出logn的空间,在有限的空间内做到了可持久化。但考虑到新建节点的下表问题,我们的左右儿子是用lson和rson特别储存下标的也就是说没有原来那种*2和 *2+1的操作。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100005
inline int read(){
    int x = 0,f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9'){ x = x*10+ch-'0'; ch = getchar(); }
    return x*f;
}

int root[N],cnt;
struct node{
    int lson,rson,sum;
}t[N<<5];
int a[N],d[N],tot;

int erfen(int x){
    int l = 1,r = tot;
    int mid;
    while(l <= r){
        mid = (l+r)>>1;
        if(d[mid] > x) r = mid-1;
        else l = mid+1;
    }
    return r;
}

void build(int &root,int l,int r){
    root = ++cnt;
    t[root].sum = 0;
    if(l == r) return;
    int mid = (l+r)>>1;
    build(t[root].lson,l,mid);
    build(t[root].rson,mid+1,r);
    return;
}

void addup(int &root1,int root2,int l,int r,int x){
    root1 = ++cnt;
    t[root1] = t[root2];
    t[root1].sum++;
    if(l == r) return;
    int mid = (l+r)>>1;
    if(x <= mid)
        addup(t[root1].lson,t[root2].lson,l,mid,x);
    else
        addup(t[root1].rson,t[root2].rson,mid+1,r,x);
}

int query(int p,int q,int l,int r,int x){
    if(r <= x) return t[q].sum-t[p].sum;
    int mid = (l+r)>>1;
    int ans = 0;
    if(l <= x) ans += query(t[p].lson,t[q].lson,l,mid,x);
    if(mid < x) ans += query(t[p].rson,t[q].rson,mid+1,r,x);
    return ans;
}

int main(){
    int t = read();
    for(int T = 1;T <= t;T++){
        cnt = 0;
        int n = read(),q = read();
        for(int i = 1;i <= n;i++)
            a[i] = d[i] = read();
        sort(d+1,d+n+1);
        tot = 1;
        for(int i = 2;i <= n;i++)
            if(d[i] != d[i-1])
                d[++tot] = d[i];
        for(int i = 1;i <= n;i++)
            a[i] = erfen(a[i]);

        build(root[0],1,tot);
        for(int i = 1;i <= n;i++)
            addup(root[i],root[i-1],1,tot,a[i]);
        printf("Case %d:\n",T);
        for(int i = 1;i <= q;i++){
            int l = read()+1,r = read()+1,x = read();
            x = erfen(x);
            if(x <= 0) printf("0\n");
            else printf("%d\n",query(root[l-1],root[r],1,tot,x));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值