Codeforces Round #179 (Div. 1) A题 线段树

有m个操作,每个操作给出l,r,d值,表示从a(l)到a(r)区间内的每个值加d。

接下来k个范围,每个范围为x到y,表示从第x个操作到第y个操作都执行一次。

输出最后得到的数组a。

两次线段树,第一次求出每种操作各需要多少次,第二次根据第一次结果求出最终结果。

代码如下

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define INF 200000000
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define maxm 200005
__int64 time[maxm<<2],lazy1[maxm<<2],cover[maxm<<2],lazy2[maxm<<2],a[maxm+5],op[maxm+5][3];
void pushdown1(__int64 rt)
{
    time[rt]+=lazy1[rt];
    lazy1[rt<<1]+=lazy1[rt];
    lazy1[rt<<1|1]+=lazy1[rt];
    lazy1[rt]=0;
}
void build1(__int64 l,__int64 r,__int64 rt)
{
    __int64 mid;
    time[rt]=0;
    lazy1[rt]=0;
    if(r>l)
    {
        mid=(l+r)>>1;
        build1(lson);
        build1(rson);
    }
}
void update1(__int64 L,__int64 R,__int64 l,__int64 r,__int64 rt)
{
    __int64 mid;
    if(L<=l&&r<=R)
    {
        lazy1[rt]++;
        return ;
    }
    pushdown1(rt);
    if(r>l)
    {
        mid=(l+r)>>1;
        if(L<=mid) update1(L,R,lson);
        if(R>mid) update1(L,R,rson);
    }
}
__int64 search1(__int64 d,__int64 l,__int64 r,__int64 rt)
{
    __int64 mid;
    pushdown1(rt);
    if(l==r)
    {
        return time[rt];
    }
    mid=(l+r)>>1;
    if(d<=mid)
        return search1(d,lson);
    else
        return search1(d,rson);
}

void build2(__int64 l,__int64 r,__int64 rt)
{
    __int64 mid;
    cover[rt]=0;
    lazy2[rt]=0;
    if(r>l)
    {
        mid=(l+r)>>1;
        build2(lson);
        build2(rson);
    }
}
void pushdown2(__int64 rt)
{
    cover[rt]+=lazy2[rt];
    lazy2[rt<<1]+=lazy2[rt];
    lazy2[rt<<1|1]+=lazy2[rt];
    lazy2[rt]=0;
}
void update2(__int64 L,__int64 R,__int64 c,__int64 l,__int64 r,__int64 rt)
{
    __int64 mid;
    if(L<=l&&r<=R)
    {
        lazy2[rt]+=c;
        return ;
    }
    pushdown2(rt);
    if(r>l)
    {
        mid=(l+r)>>1;
        if(L<=mid)update2(L,R,c,lson);
        if(R>mid)update2(L,R,c,rson);
    }
}
__int64 search2(__int64 d,__int64 l,__int64 r,__int64 rt)
{
    __int64 mid;
    pushdown2(rt);
    if(l==r)
        return cover[rt];
    mid=(l+r)>>1;
    if(d<=mid)
        return search2(d,lson);
    else
        return search2(d,rson);
}
int main()
{
    __int64 i,j,k,l,n,m,kk,le,ri;
    while(scanf("%I64d%I64d%I64d",&n,&m,&kk)!=EOF)
    {
        for(i=1;i<=n;i++)
            scanf("%I64d",&a[i]);
        for(i=1;i<=m;i++)
            scanf("%I64d%I64d%I64d",&op[i][0],&op[i][1],&op[i][2]);
        build1(1,m,1);
        for(i=1;i<=kk;i++)
        {
            scanf("%I64d%I64d",&le,&ri);
            update1(le,ri,1,m,1);
        }
        build2(1,n,1);
        for(i=1;i<=m;i++)
        {
            j=op[i][2];
            k=search1(i,1,m,1);
            update2(op[i][0],op[i][1],j*k,1,n,1);
        }
        for(i=1;i<n;i++)
            printf("%I64d ",a[i]+search2(i,1,n,1));
        printf("%I64d\n",a[i]+search2(i,1,n,1));
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值