Super Mario HDU - 4417

点击打开链接

两种做法

主席树模板题 对两个版本的线段树进行区间查询 然后做差即可

#include <bits/stdc++.h>
using namespace std;

struct node
{
    int nl;
    int nr;
    int val;
};

map <int,int> mp;
node tree[2000010];
int num[100010],pre[100010],root[100010];
int n,m,tot;

int build(int l,int r)
{
    int cur,m;
    cur=tot++;
    tree[cur].nl=0,tree[cur].nr=0,tree[cur].val=0;
    if(l==r) return cur;
    m=(l+r)/2;
    tree[cur].nl=build(l,m);
    tree[cur].nr=build(m+1,r);
    return cur;
}

int update(int rot,int tar,int l,int r)
{
    int cur,m;
    cur=tot++;
    tree[cur]=tree[rot];
    tree[cur].val++;
    if(l==r) return cur;
    m=(l+r)/2;
    if(tar<=m) tree[cur].nl=update(tree[cur].nl,tar,l,m);
    else tree[cur].nr=update(tree[cur].nr,tar,m+1,r);
    return cur;
}

int query(int lrot,int rrot,int pl,int pr,int l,int r)
{
    int res,cur,m;
    if(pl<=l&&r<=pr)
    {
        return tree[rrot].val-tree[lrot].val;
    }
    res=0,m=(l+r)/2;
    if(pl<=m) res+=query(tree[lrot].nl,tree[rrot].nl,pl,pr,l,m);
    if(pr>m) res+=query(tree[lrot].nr,tree[rrot].nr,pl,pr,m+1,r);
    return res;
}

int main()
{
    int t,cas,q,i,l,r,h,p;
    scanf("%d",&t);
    for(cas=1;cas<=t;cas++)
    {
        scanf("%d%d",&n,&q);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            pre[i]=num[i];
        }
        sort(pre+1,pre+n+1);
        mp.clear();
        for(i=1,m=0;i<=n;i++)
        {
            if(m==0||pre[m]!=pre[i])
            {
                pre[++m]=pre[i];
                mp[pre[m]]=m;
            }
        }
        tot=0;
        root[0]=build(1,n);
        for(i=1;i<=n;i++)
        {
            root[i]=update(root[i-1],mp[num[i]],1,n);
        }
        printf("Case %d:\n",cas);
        while(q--)
        {
            scanf("%d%d%d",&l,&r,&h);
            l++,r++;
            p=upper_bound(pre+1,pre+m+1,h)-pre-1;
            if(p>=1) printf("%d\n",query(root[l-1],root[r],1,p,1,n));
            else printf("0\n");
        }
    }
    return 0;
}

 

线段树离线处理 把询问按h值排序 对每一个查询 把所有小于等于该查询h值的数都在线段树对应位置上更新

#include <bits/stdc++.h>
using namespace std;

struct node1
{
    int l;
    int r;
    int val;
};

struct node2
{
    int id;
    int val;
};

struct node3
{
    int l;
    int r;
    int h;
    int id;
    int val;
};

node1 tree[400010];
node2 ary[100010];
node3 order[100010];
int n,q;

bool cmpI(node2 n1,node2 n2)
{
    return n1.val<n2.val;
}

bool cmpII(node3 n1,node3 n2)
{
    return n1.h<n2.h;
}

bool cmpIII(node3 n1,node3 n2)
{
    return n1.id<n2.id;
}

void build(int l,int r,int cur)
{
    int m;
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].val=0;
    if(l==r) return;
    m=(l+r)/2;
    build(l,m,2*cur);
    build(m+1,r,2*cur+1);
}

void update(int tar,int cur)
{
    tree[cur].val++;
    if(tree[cur].l==tree[cur].r) return;
    if(tar<=tree[2*cur].r) update(tar,2*cur);
    else update(tar,2*cur+1);
}

int query(int pl,int pr,int cur)
{
    int res;
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        return tree[cur].val;
    }
    res=0;
    if(pl<=tree[2*cur].r) res+=query(pl,pr,2*cur);
    if(pr>=tree[2*cur+1].l) res+=query(pl,pr,2*cur+1);
    return res;
}

int main()
{
    int t,cas,i,pos;
    scanf("%d",&t);
    for(cas=1;cas<=t;cas++)
    {
        scanf("%d%d",&n,&q);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&ary[i].val);
            ary[i].id=i;
        }
        sort(ary+1,ary+n+1,cmpI);
        for(i=1;i<=q;i++)
        {
            scanf("%d%d%d",&order[i].l,&order[i].r,&order[i].h);
            order[i].l++,order[i].r++;
            order[i].id=i;
        }
        sort(order+1,order+q+1,cmpII);
        build(1,n,1);
        pos=1;
        for(i=1;i<=q;i++)
        {
            while(pos<=n&&ary[pos].val<=order[i].h)
            {
                update(ary[pos].id,1);
                pos++;
            }
            order[i].val=query(order[i].l,order[i].r,1);
        }
        sort(order+1,order+q+1,cmpIII);
        printf("Case %d:\n",cas);
        for(i=1;i<=q;i++)
        {
            printf("%d\n",order[i].val);
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值