牛客练习赛28 B【线段树+区间和+区间平方和+区间修改】

链接:https://www.nowcoder.com/acm/contest/200/B
来源:牛客网

题目描述

qn姐姐最好了~

    qn姐姐给你了一个长度为n的序列还有m次操作让你玩,

    1 l r 询问区间[l,r]内的元素和

    2 l r 询问区间[l,r]内的元素的平方 

    3 l r x 将区间[l,r]内的每一个元素都乘上x

    4 l r x 将区间[l,r]内的每一个元素都加上x

输入描述:

第一行两个数n,m

接下来一行n个数表示初始序列

就下来m行每行第一个数为操作方法opt,

若opt=1或者opt=2,则之后跟着两个数为l,r

若opt=3或者opt=4,则之后跟着三个数为l,r,x

操作意思为题目描述里说的

输出描述:

对于每一个操作1,2,输出一行表示答案

 

示例1

输入

5 6
1 2 3 4 5
1 1 5
2 1 5
3 1 2 1
4 1 3 2
1 1 4
2 2 3

输出

15
55
16
41

备注:

对于100%的数据 n=10000,m=200000 (注意是等于号)

保证所有询问的答案在long long 范围内

题解:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 10010;
int n, m;
struct SegmentTree{
    int l, r;
    ll sum1, sum2, add, mul;
    #define l(p) t[p].l
    #define r(p) t[p].r
    #define sum1(p) t[p].sum1
    #define sum2(p) t[p].sum2
    #define add(p) t[p].add
    #define mul(p) t[p].mul
}t[maxn<<2];
ll a[maxn];
void push_up(int p){
    sum1(p) = sum1(p<<1) + sum1(p<<1|1);
    sum2(p) = sum2(p<<1) + sum2(p<<1|1);
}
void push_down(int p){
    if(mul(p) != 1){
        mul(2*p) *= mul(p);
        mul(2*p+1) *= mul(p);
        if(add(2*p)) add(2*p) *= mul(p);
        if(add(2*p+1)) add(2*p+1) *= mul(p);
        sum1(2*p) *= mul(p);
        sum1(2*p+1) *= mul(p);
        sum2(2*p) *= (mul(p)*mul(p));
        sum2(2*p+1) *= (mul(p)*mul(p));
        mul(p) = 1;
    }
    if(add(p)){
        add(2*p) += add(p);
        add(2*p+1) += add(p);
        sum2(2*p) += ((r(2*p)-l(2*p)+1)*add(p)*add(p) + 2*sum1(2*p)*add(p));
        sum2(2*p+1) += ((r(2*p+1)-l(2*p+1)+1)*add(p)*add(p) + 2*sum1(2*p+1)*add(p));
        sum1(2*p) += add(p)*(r(2*p)-l(2*p)+1);
        sum1(2*p+1) += add(p)*(r(2*p+1)-l(2*p+1)+1);
        add(p) = 0;
    }
}
void build(int p, int l, int r){
    l(p) = l, r(p) = r;
    add(p) = 0, mul(p) = 1;
    if(l == r){
        sum1(p) = a[l];
        sum2(p) = a[l] * a[l];
        return ;
    }
    int mid = (l+r)>>1;
    build(2*p, l, mid);
    build(2*p+1, mid+1, r);
    push_up(p);
}
void change(int p, int l, int r, int c, int op){
    if(l <= l(p) && r >= r(p)){
        if(op == 3){
            mul(p) = mul(p)*c;
            if(add(p)) add(p) = add(p)*c;
            sum1(p) = sum1(p)*c;
            sum2(p) = sum2(p)*c*c;
        }else{
            add(p) +=  c;
            sum2(p) += (r(p)-l(p)+1)*c*c + 2*sum1(p)*c;
            sum1(p) += (r(p)-l(p)+1)*c;
        }
        return ;
    }
    push_down(p);
    int mid = (l(p)+r(p)) / 2;
    if(l <= mid) change(2*p, l, r, c, op);
    if(r > mid) change(2*p+1, l, r, c, op);
    push_up(p);
}
ll ask(int p, int l, int r, int op){
    if(l <= l(p) && r >= r(p)){
        if(op == 1) return sum1(p);
        if(op == 2) return sum2(p);
    }
    push_down(p);
    int mid = (l(p)+r(p))/2;
    ll sum = 0;
    if(l <= mid) sum += ask(2*p, l, r, op);
    if(r > mid) sum += ask(2*p+1, l, r, op);
    return sum;
}
int main()
{
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++){
        scanf("%lld\n", &a[i]);
    }
    build(1, 1, n);
    int op, l, r, x;
    while(m--){
        scanf("%d %d %d", &op, &l, &r);
        if(op == 1){
            printf("%lld\n", ask(1, l, r, 1));
        }else if(op == 2){
            printf("%lld\n", ask(1, l, r, 2));
        }else if(op == 3){
            scanf("%d", &x);
            change(1, l, r, x, 3);
        }else{
            scanf("%d", &x);
            change(1, l, r, x, 4);
        }
    }
    return 0;
}

 

    原文作者:B树
    原文地址: https://blog.csdn.net/qq_37867156/article/details/82947597
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞