<题目链接>

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. nginx安装目录详解(针对centos)

  2. Java的动手动脑(六)

    日期:2018.11.8 星期四 博客期:022 --------------------------------------------------------------------------- ...

  3. vue的基础知识

    Vue.js是什么? Vue(法语)同view(英语) Vue.js是一套构建用户界面(view)的MVVM框架.Vue.js的核心库只关注视图层,并且非常容易学习,非常容易与其他库或已有的项目整合. ...

  4. CentOS 7 安装 Redis

    1.Redis 下载地址:https://redis.io/download 2.上传到服务器指定文件夹 ,我这边传到了根目录下 /mysoft 这个目录下 解压  tar  -zxvf redis- ...

  5. 数据库MySql的安装

    1.MySQL概述 MySQL最初是由“MySQL AB公司”开发的一套关系型数据库管理系统(RDBMS-Relation DataBase Management System).MySQL不仅是最流 ...

  6. 第四周学习总结-HTML

    2018年8月5日 这是暑假第四周,这一周我在菜鸟教程网学到了许多HTML的知识.HTML编写网页不像C语言.Java语言那必须有主方法.主函数什么的,它基本上都是标签(元素),但是它可以与CSS(层 ...

  7. linux学习笔记之 basename, dirname

    前言: basename: 用于打印目录或者文件的基本名称 dirname: 去除文件名中的非目录部分,仅显示与目录有关的内容.dirname命令读取指定路径名保留最后一个/及其后面的字符,删除其他部 ...

  8. extjs5(项目中文件的加载过程)

    现在来看看js类加载过程.如下图所示: 1、首先:浏览器中输入 localhost:1841 ,调用 index.html; <!DOCTYPE HTML> <html> &l ...

  9. C. cltt的幸运数LCAdfs

    /*C: cltt的幸运数 Time Limit: 1 s      Memory Limit: 128 MB Submit Problem Description 一棵树有n个节点,共m次查询,查询 ...

  10. tp3.2上传图片生成缩略图

    //引入 use think\Image; /* * $name为表单上传的name值 * $filePath为为保存在入口文件夹public下面uploads/下面的文件夹名称,没有的话会自动创建 ...