数据结构--线段树--牛客练习赛28B

https://www.nowcoder.com/acm/contest/200/B

op = 1 sum

op = 2 sum2 平方和

op = 3 *mul

op = 4 +add

2个lazy标记

#include <cstdio>
#include <iostream>
using namespace std;
#define lc (rt << 1)
#define rc (rt << 1 | 1)
#define mid (l + r) / 2

typedef long long ll;
const int maxn = 1e4 + 5;
ll a[maxn];
ll sum[maxn << 2],sum2[maxn << 2];
ll _sum,_sum2;
ll mul[maxn << 2];
ll add[maxn << 2];

void init(int l,int r,int rt)
{
    if(l == r){
        sum[rt] = a[l];
        sum2[rt] = a[l] * a[l];
        mul[rt] = 1;
        add[rt] = 0;
        return;
    }
    init(l,mid,lc);
    init(mid + 1,r,rc);
    sum[rt] = sum[lc] + sum[rc];
    sum2[rt] = sum2[lc] + sum2[rc];
    mul[rt] = 1;
    add[rt] = 0;
}
//一定要先更新sum2,因为它用到了旧的sum
//如果2个标记分开处理,先确定顺序,第一个标记除了update中操作,还更新d第二个标记;第二个标记就是update操作
void pushdown(int l,int r,int rt)
{
    if(mul[rt] != 1){
        mul[lc] *= mul[rt];mul[rc] *= mul[rt];
        add[lc] *= mul[rt];
        add[rc] *= mul[rt];
        sum2[lc] *= mul[rt] * mul[rt];sum2[rc] *= mul[rt] * mul[rt];
        sum[lc] *= mul[rt];sum[rc] *= mul[rt];
        mul[rt] = 1;
    }
    if(add[rt] != 0){
        add[lc] += add[rt];add[rc] += add[rt];
        sum2[lc] += 2 * sum[lc] * add[rt] + (mid - l + 1) * add[rt] * add[rt];
        sum2[rc] += 2 * sum[rc] * add[rt] + (r - mid) * add[rt] * add[rt];
        sum[lc] += add[rt] * (mid - l + 1);sum[rc] += add[rt] * (r - mid);
        add[rt] = 0;
    }

}
//左子树原x1*a+y1 将父节点传递->x*(x1*a+y1)+y
//void pushdown(int l,int r,int rt)
//{
//    if(mul[rt] == 1 && add[rt] == 0) return;
//    mul[lc] *= mul[rt];mul[rc] *= mul[rt];
//    add[lc] = add[lc] * mul[rt] + add[rt];
//    add[rc] = add[rc] * mul[rt] + add[rt];
//    sum2[lc] = mul[rt] * mul[rt] * sum2[lc] + 2 * mul[rt] * add[rt] * sum[lc] + (mid - l + 1) * add[rt] * add[rt];
//    sum2[rc] = mul[rt] * mul[rt] * sum2[rc] + 2 * mul[rt] * add[rt] * sum[rc] + (r - mid) * add[rt] * add[rt];
//
//    sum[lc] = sum[lc] * mul[rt] + add[rt] * (mid - l + 1);
//    sum[rc] = sum[rc] * mul[rt] + add[rt] * (r - mid);
//    mul[rt] = 1;add[rt] = 0;
//}
void query(int ql,int qr,int l,int r,int rt)
{
   if(ql <= l && r <= qr){
        _sum += sum[rt];
        _sum2 += sum2[rt];
        return;
    }
    pushdown(l,r,rt);
    if(ql <= mid) query(ql,qr,l,mid,lc);
    if(mid < qr) query(ql,qr,mid + 1,r,rc);
}
void update1(int ql,int qr,int l,int r,int rt,ll x)
{
    if(ql <= l && r <= qr){
        sum2[rt] *= x * x;
        sum[rt] *= x;
        mul[rt] *= x;
        return;
    }
    pushdown(l,r,rt);
    if(ql <= mid) update1(ql,qr,l,mid,lc,x );
    if(mid < qr) update1(ql,qr,mid + 1,r,rc,x );
    sum[rt] = sum[lc] + sum[rc];
    sum2[rt] = sum2[lc] + sum2[rc];
}
void update2(int ql,int qr,int l,int r,int rt,ll x)
{
    if(ql <= l && r <= qr){
        sum2[rt] += 2 * x * sum[rt] + (r - l + 1) * x * x;
        sum[rt] += x * (r - l + 1);
        add[rt] += x;
        return;
    }
    pushdown(l,r,rt);
    if(ql <= mid) update2(ql,qr,l,mid,lc,x );
    if(mid < qr) update2(ql,qr,mid + 1,r,rc,x );
    sum[rt] = sum[lc] + sum[rc];
    sum2[rt] = sum2[lc] + sum2[rc];
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++) scanf("%lld",&a[i]);
    init(1,n,1);
    int op,ql,qr;
    ll x;
    for(int i =0 ;i < m;i ++){
        scanf("%d",&op);
        _sum = _sum2 = 0;
        if(op == 1){
            scanf("%d%d",&ql,&qr);
            query(ql,qr,1,n,1);
            printf("%lld\n",_sum);
        }
        else if(op == 2){
            scanf("%d%d",&ql,&qr);
            query(ql,qr,1,n,1);
            printf("%lld\n",_sum2);
        }
        else if(op == 3){
            scanf("%d%d%lld",&ql,&qr,&x);
            update1(ql, qr, 1, n, 1, x);
        }
        else if(op == 4){
            scanf("%d%d%lld",&ql,&qr,&x);
            update2(ql,qr,1,n,1,x);
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值