链接: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;
}