题解 P2184 【贪婪大陆】

我看见没有C++的线段树写法,所以来发一波题解。

这是一个代码简单的线段树,但其实不是很容易想到这种思路。

线段树要维护两个东西,一个suml(起点),sumr(终点);

插入:

插入的时候只需要在起点和终点sum++(区间维护,实际是点修改),如图:

查询:

查询x ~ y区间的时候需要用1~ y点的suml - 1 ~ x点的sumr;

为什么这样查询呢?大家仔细想想,用笔画画,这是个区间覆盖问题,大家一定要想通,结合插入来想想。(这里就不详细讲了,结合图片看看)。

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rs id<<1|1
#define ls id<<1
using namespace std;
const int N=100000+10;
struct node
{
    int left,right,sumr,suml;
}tree[N*4];
int n,m;
void build(int id,int l,int r)
{
    tree[id].left=l,tree[id].right=r;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(ls,l,mid),build(rs,mid+1,r);
}
void update(int id,int x)//修改起点
{
    if(tree[id].left==tree[id].right)
    {
        tree[id].suml++;return;
    }
    if(x>tree[ls].right)update(rs,x);
    else update(ls,x);
    tree[id].suml=tree[ls].suml+tree[rs].suml;
}
void update2(int id,int x)//修改终点
{
    if(tree[id].left==tree[id].right)
    {
        tree[id].sumr++;return;
    }
    if(x>tree[ls].right)update2(rs,x);
    else update2(ls,x);
    tree[id].sumr=tree[ls].sumr+tree[rs].sumr;
}
int query(int id,int l,int r)//查询起点
{
    if(r<tree[id].left || tree[id].right<l)return 0;
    if(l<=tree[id].left&&tree[id].right<=r)return tree[id].suml;
    return query(ls,l,r)+query(rs,l,r);
}
int query2(int id,int l,int r)//查询终点
{
    if(tree[id].left>r||tree[id].right<l)return 0;
    if(tree[id].left>=l&&tree[id].right<=r)return tree[id].sumr;
    return query2(ls,l,r)+query2(rs,l,r);
}
int main()
{
    scanf("%d%d",&n,&m);
    build(1,1,n);//建树
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==1)
        {
            update(1,y);update2(1,z);
        }
        if(x==2)
        {
            int s=query(1,1,z);
            int t=query2(1,1,y-1);
            printf("%d\n",s-t);//终点的sum-起点的sum
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SNiFe_Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值