Super Mario HDU - 4417 主席树模板(二)

Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss’s castle as a line (the length is n), on every integer point i there is a brick on height hi. Now the question is how many bricks in [L, R] Mario can hit if the maximal height he can jump is H.

Input

The first line follows an integer T, the number of test data. 
For each test data: 
The first line contains two integers n, m (1 <= n <=10^5, 1 <= m <= 10^5), n is the length of the road, m is the number of queries. 
Next line contains n integers, the height of each brick, the range is [0, 1000000000]. 
Next m lines, each line contains three integers L, R,H.( 0 <= L <= R < n 0 <= H <= 1000000000.)

Output

For each case, output "Case X: " (X is the case number starting from 1) followed by m lines, each line contains an integer. The ith integer is the number of bricks Mario can hit for the ith query. 

Sample Input

1
10 10
0 5 2 7 5 4 3 8 7 7 
2 8 6
3 5 0
1 3 1
1 9 4
0 1 0
3 5 5
5 5 1
4 6 3
1 5 7
5 7 3

Sample Output

Case 1:
4
0
0
3
1
2
0
1
5
1
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<iostream>
using namespace std;
const int maxn=100005;
struct node
{
    int l,r,sum;
}tree[maxn*20];//仅包含左右儿子编号和出现数个数,不包含本节点编号
int sca[maxn],disc[maxn],root[maxn];//sca输入,disc sca的离散化,root根节点编号
int interval,cnt;//interval主席树总区间大小,也是disc中数的个数,cnt建树用编号
void init()
{
    cnt=0;//tree不用初始化,因为建树是基于tree[0]的,而tree[0]中值始终为0
}
int getind(int x){return lower_bound(disc,disc+interval,x)-disc;}//二分查找离散化后的值
void build(int l,int r,int &now,int bef,int pos)//需要传入l和r,因为第一条链是依据tree[0]建立的,需要l和r作为边界,无法依靠前一条链
//now是正在建立的链中正在建立的节点,必须是引用,因为需要将上一个节点的需要更改的儿子指向该节点
//bef是正在建立的节点在上一条链中对应的节点,pos是要添加的值,注意必须是离散化后的值
{
    now=++cnt;//代表新节点的建立,同时上一个节点需要更改的儿子的指向已经改变
    tree[now]=tree[bef];tree[now].sum++;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(pos<=mid) build(l,mid,tree[now].l,tree[bef].l,pos);//将需要改变的儿子传下去
    else build(mid+1,r,tree[now].r,tree[bef].r,pos);
}
int query(int l,int r,int chain_l,int chain_r,int pos)//pos是离散化后的值
{//chain_l和chain_r是左右时间截
    if(l==r) return tree[chain_r].sum-tree[chain_l].sum;
    //注意当pos不在主席树的总覆盖区间内时,区间右边界会不断向左边靠近,直至左右边界重合,触发该判断,要注意特判
    int mid=(l+r)>>1;
    int sum=tree[tree[chain_r].l].sum-tree[tree[chain_l].l].sum;
    if(pos<=mid) return query(l,mid,tree[chain_l].l,tree[chain_r].l,pos);//当覆盖的左半区间大于查询区间时缩小覆盖区间
    else return sum+query(mid+1,r,tree[chain_l].r,tree[chain_r].r,pos);//当覆盖的左半区间小于查询区间时结算左半区间,向右半区间查询
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int Case=1;Case<=t;Case++)
    {
        init();
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&sca[i]);
            disc[i-1]=sca[i];
        }
        sort(disc,disc+n);
        interval=unique(disc,disc+n)-disc;//离散化结束后值从0开始
        for(int i=1;i<=n;i++)
            build(0,interval,root[i],root[i-1],getind(sca[i]));
        printf("Case %d:\n",Case);
        for(int i=1;i<=m;i++)
        {
            int chain_l,chain_r,pos;
            scanf("%d %d %d",&chain_l,&chain_r,&pos);
            chain_l++,chain_r++;
            int ind=getind(pos);
            if(disc[ind]!=pos) ind--;
            if(ind==-1) printf("0\n");//仅当pos小于sca中最小值时会出现ind超出主席树总覆盖区间的情况,这时需要特判,当pos大于sca中
            //最大值时ind会等于离散化后的最大值
            else printf("%d\n",query(0,interval,root[chain_l-1],root[chain_r],ind));
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值