<题目链接>

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,输出一行表示答案

输入

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 范围内

解题分析:
本题主要的难点在于,对区间进行加或者乘上一个数后,如何快速的维护每个节点的sum 和pfh(区间所有数平方和) 值,如果仅仅是对区间的每个节点进行暴力单点更新的话,毫无疑问会超时。所以我们必须对区间整体修改,而且我们要想到,在区间的维度上,是可以对该区间的每个数平方和进行修改的,它并不像开根号一样,必须要下放到每个叶子节点,对具体的数进行开根。区间修改pfh值时,只需要利用平方和展开式,就能很容易的对区间平方和进行修改。

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; #define Lson rt<<1,l,mid
#define Rson rt<<1|1,mid+1,r
typedef long long ll;
const int M = 1e4+;
ll n,m,arr[M];
struct Tree{
ll sum,pfh,add,mul;
}tr[M<<];
void Pushup(ll rt){
tr[rt].sum=tr[rt<<].sum+tr[rt<<|].sum;
tr[rt].pfh=tr[rt<<].pfh+tr[rt<<|].pfh; //pfh记录的是该区间所有元素的平方和
}
void Pushdown(ll rt,ll len){ //mul和add相当于两个lazy标记
if(tr[rt].mul!=){
ll tmp=tr[rt].mul;
tr[rt<<].sum*=tmp,tr[rt<<|].sum*=tmp;
tr[rt<<].pfh=tr[rt<<].pfh*tmp*tmp,tr[rt<<|].pfh=tr[rt<<|].pfh*tmp*tmp; //相当于对该区间的每个数都进行平方
tr[rt<<].mul*=tmp,tr[rt<<|].mul*=tmp; //这几个标记都要*mul
tr[rt<<].add*=tmp,tr[rt<<|].add*=tmp;
tr[rt].mul=;
}
if(tr[rt].add){
ll tmp=tr[rt].add;
tr[rt<<].pfh=tr[rt<<].pfh+*tmp*tr[rt<<].sum+tmp*tmp*(len-(len>>)); //注意这里,要将更新pfh的语句放在更新sum的语句之前
tr[rt<<|].pfh=tr[rt<<|].pfh+*tmp*tr[rt<<|].sum+tmp*tmp*(len>>);
tr[rt<<].sum+=tmp*(len-(len>>)),tr[rt<<|].sum+=tmp*(len>>);
tr[rt<<].add+=tmp,tr[rt<<|].add+=tmp;
tr[rt].add=;
}
}
void build(ll rt,ll l,ll r){
tr[rt].add=,tr[rt].mul=;
if(l==r){
tr[rt].sum=arr[l],tr[rt].pfh=arr[l]*arr[l];
return;
}
ll mid=(l+r)>>;
build(Lson);
build(Rson);
Pushup(rt);
}
void update1(ll rt,ll l,ll r,ll L,ll R,ll c){
if(L<=l&&r<=R){
tr[rt].sum*=c,tr[rt].add*=c,tr[rt].mul*=c;
tr[rt].pfh*=tr[rt].pfh*c*c;
return;
}
Pushdown(rt,r-l+);
ll mid=(l+r)>>;
if(L<=mid)update1(Lson,L,R,c);
if(R>mid)update1(Rson,L,R,c);
Pushup(rt);
}
void update2(ll rt,ll l,ll r,ll L,ll R,ll c){
if(L<=l&&r<=R){
tr[rt].pfh=tr[rt].pfh+*c*tr[rt].sum+c*c*(r-l+); //注意这里,要将更新pfh的语句放在更新sum的语句之前
tr[rt].add+=c;
tr[rt].sum+=c*(r-l+);
return;
}
Pushdown(rt,r-l+);
ll mid=(l+r)>>;
if(L<=mid)update2(Lson,L,R,c);
if(R>mid)update2(Rson,L,R,c);
Pushup(rt);
}
ll query(ll rt,ll l,ll r,ll L,ll R,ll ty){
if(L<=l&&r<=R){
if(ty==)return tr[rt].sum;
else return tr[rt].pfh;
}
Pushdown(rt,r-l+);
ll mid=(l+r)>>;
ll ans=;
if(L<=mid)ans+=query(Lson,L,R,ty);
if(R>mid)ans+=query(Rson,L,R,ty);
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
for(int i=;i<=n;i++)scanf("%lld",&arr[i]);
build(,,n);
while(m--){
ll op,x,y,c;
scanf("%lld%lld%lld",&op,&x,&y);
if(op==||op==){
printf("%lld\n",query(,,n,x,y,op));
}
else{
scanf("%lld",&c);
if(op==)update1(,,n,x,y,c);
else update2(,,n,x,y,c);
}
}
return ;
}


2018-10-05

牛客练习赛28B (经典)【线段树】的更多相关文章

  1. 牛客练习赛28-B(线段树,区间更新)

    牛客练习赛28 - B 传送门 题目 qn姐姐最好了~ ​ qn姐姐给你了一个长度为n的序列还有m次操作让你玩, ​ 1 l r 询问区间[l,r]内的元素和 ​ 2 l r 询问区间[l,r]内的 ...

  2. 牛客练习赛63 牛牛的树行棋 差分 树上博弈 sg函数

    LINK:牛牛的树行棋 本来是不打算写题解的. 不过具体思考 还是有一段时间的. 看完题 一直想转换到阶梯NIM的模型上 转换失败. 考虑SG函数. 容易发现 SG函数\(sg_x=max{sg_{t ...

  3. 牛客练习赛52 B Galahad (树状数组)

    题目链接:https://ac.nowcoder.com/acm/contest/1084/B 题意 5e5的区间,5e5个询求[l,r]区间内出现过的数的和 思路 1s时限,莫队显然会T 我们可以将 ...

  4. 牛客练习赛70 D.数树 (模拟,STL)

    题意:每次有\(3\)中操作,对两个点连条边,删去某条边,或者问当前大小不为\(1\)的树的数量.连重边或者删去一条不存在的边,这样的白痴操作可以无视qwq. 题解:水题,用map存一下pair然后分 ...

  5. 牛客练习赛 29 E 位运算?位运算!(线段树)

    题目链接  牛客练习赛29E 对$20$位分别建立线段树.首先$1$和$2$可以合起来搞(左移右移其实是等效的) 用个lazy标记下.转移的时候加个中间变量. $3$和$4$其实就是区间$01$覆盖操 ...

  6. 牛客练习赛11 假的字符串 (Trie树+拓扑找环)

    牛客练习赛11 假的字符串 (Trie树+拓扑找环) 链接:https://ac.nowcoder.com/acm/problem/15049 来源:牛客网 给定n个字符串,互不相等,你可以任意指定字 ...

  7. 【并查集缩点+tarjan无向图求桥】Where are you @牛客练习赛32 D

    目录 [并查集缩点+tarjan无向图求桥]Where are you @牛客练习赛32 D PROBLEM SOLUTION CODE [并查集缩点+tarjan无向图求桥]Where are yo ...

  8. ZOJ - 1610 经典线段树染色问题

    这个是一个经典线段树染色问题,不过题目给的是左右左右坐标,即[0,3]包含0-1这一段 1-2这一段 2-3这一段,和传统的染色不太一样,不过其实也不用太着急. 我们把左边的坐标+1,即可,那么[0, ...

  9. 牛客练习赛31 B 赞迪卡之声妮莎与奥札奇 逻辑,博弈 B

    牛客练习赛31 B 赞迪卡之声妮莎与奥札奇 https://ac.nowcoder.com/acm/contest/218/B 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 2621 ...

随机推荐

  1. iOS UIDatePicker设置为中文的方法

    UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 20, 200, 30)]; datePick ...

  2. Mybaits动态Sql

    什么是动态SQL? MyBatis的强大之处便是它的动态SQL,如果你使用JDBC那么在根据不同条件查询时,拼接SQL语句是多么的痛苦. 比如查询一个学生信息,可以根据学生的姓名,性别,班级,年龄,学 ...

  3. yum安装软件内容

    linux  yum源改为阿里yum源 1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.back ...

  4. C++ Primer 笔记——union

    1.union是一种特殊的类.一个union可以有多个数据成员,但是在任意时刻,只有一个数据成员可以有值.当我们给union的某个成员赋值之后,该union的其他成员就变成未定义的状态了.分配给一个u ...

  5. 将眼底图片生成的txt文件进行格式化处理

    # -*- coding: utf-8 -*- """ 将图片转换生成的txt文件进行格式化处理 """ import os import ...

  6. GoogleTest入门

    Googletest入门 来源:https://github.com/google/googletest/blob/master/googletest/docs/primer.md P.S. gmoc ...

  7. Nlog日志之File

    一:简介 NLog是一个简单灵活的.NET日志记录类库.通过使用NLog,我们可以在任何一种.NET语言中输出带有上下文的(contextual information)调试诊断信息,根据喜好配置其表 ...

  8. C#学习-析构函数

    析构函数用于在类销毁之前释放类实例所使用的托管和非托管资源. 对于C#应用程序所创建的大多数对象,可以依靠.NET Framework的垃圾回收器(GC)来隐式地执行内存管理任务. 但是,若创建封装了 ...

  9. Jhipster Registry(Eureka Server) Docker双向联通与高可用部署

    使用Compose来编排这个Eureka Server集群: peer1配置: server: port: 8761 eureka: instance: hostname: eureka-peer-1 ...

  10. MaterialEditText——Android Material Design EditText控件

    MaterialEditText是Android Material Design EditText控件.可以定制浮动标签.主要颜色.默认的错误颜色等. 随着 Material Design 的到来, ...