HDU 4107 Gangster (线段树)

       这道题,一看题大概就知道是线段树。

       对于这种题通常来说就是看节点中如何记录信息了……

       这道题我们使用:

v记录区间的改变值,也就是在update过程中累加的改变值

Max表示整个区间的最大值

Min表示整个区间的最小值

当然还有l和r不用说了。

        当一个区间的Max<p的时候我们就对这个区间的v值加上c,当一个区间的的Min>=p的时候,我们就将这个区间的v值加上2*c;等到所有的update完成之后,直接查询每个点的v值就是最终输出的答案了……

         如果不会写可以看下代码:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
const int Max= 200010;
typedef struct SEGMENT
{
    int l,r;
    int v,Max,Min;
}Segment;
Segment seg[Max*4];

int n,m,p;

int inline max(int a,int b)
{
    if(a<b) return b;
    else    return a;
}
int inline min(int a,int b)
{
    if(a<b) return a;
    else    return b;
}

void init(int l,int r,int k)
{
    seg[k].l=l,seg[k].r=r;
    seg[k].v=seg[k].Max=seg[k].Min=0;
    if(l==r)
        return ;
    init(l,(l+r)>>1,k<<1);
    init(((l+r)>>1)+1,r,(k<<1)+1);
}

void inline pushDown(int k)
{
    int v=seg[k].v;
    if(seg[k].v>0)
    {
        seg[k<<1].v+=seg[k].v,seg[k<<1].Min+=v,seg[k<<1].Max+=v;
        seg[(k<<1)+1].v+=seg[k].v,seg[(k<<1)+1].Min+=v,seg[(k<<1)+1].Max+=v;
        seg[k].v=0;
    }
}

void inline pushUp(int k)
{
    seg[k].Max=max(seg[k<<1].Max,seg[(k<<1)+1].Max);
    seg[k].Min=min(seg[k<<1].Min,seg[(k<<1)+1].Min);
}

void update(int l,int r,int c,int k)
{
    if(seg[k].l==l&&seg[k].r==r&&(seg[k].Max<p||seg[k].Min>=p))
    {
        if(seg[k].Max<p)
        {
            seg[k].v+=c;
            seg[k].Max+=c;
            seg[k].Min+=c;
        }

        else if(seg[k].Min>=p)
        {
            seg[k].v+=(c<<1);
            seg[k].Max+=(c<<1);
            seg[k].Min+=(c<<1);
        }
        return ;
    }
    if(seg[k].v)
        pushDown(k);
    int mid=(seg[k].l+seg[k].r)>>1;
    if(r<=mid)
        update(l,r,c,k<<1);
    else if(l>mid)
        update(l,r,c,(k<<1)+1);
    else
    {
        update(l,mid,c,2*k);
        update(mid+1,r,c,2*k+1);
    }
    pushUp(k);
}

int read(int id,int k)
{
    if(seg[k].l==id&&seg[k].r==id)
    {
        return seg[k].v;
    }
    if(seg[k].v>0)
        pushDown(k);
    int mid=(seg[k].l+seg[k].r)>>1;
    if(id<=mid)
        return read(id,k<<1);
    else if(id>mid)
        return read(id,(k<<1)+1);
}

int main()
{
    int a,b,c;
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        init(1,n,1);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            update(a,b,c,1);
        }
        for(int i=1;i<=n;i++)
        {
            printf("%d%c",read(i,1),i==n?'\n':' ');
        }
    }
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值