题目描述 Description

有n个数和5种操作

add a b c:把区间[a,b]内的所有数都增加c

set a b c:把区间[a,b]内的所有数都设为c

sum a b:查询区间[a,b]的区间和

max a b:查询区间[a,b]的最大值

min a b:查询区间[a,b]的最小值

输入描述 Input Description

第一行两个整数n,m,第二行n个整数表示这n个数的初始值

接下来m行操作,同题目描述

输出描述 Output Description

对于所有的sum、max、min询问,一行输出一个答案

样例输入 Sample Input

10 6

3 9 2 8 1 7 5 0 4 6

add 4 9 4

set 2 6 2

add 3 8 2

sum 2 10

max 1 7

min 3 6

样例输出 Sample Output

49

11

4

数据范围及提示 Data Size & Hint

10%:1<n,m<=10

30%:1<n,m<=10000

100%:1<n,m<=100000

保证中间结果在long long(C/C++)、int64(pascal)范围内

正解:线段树

解题报告:

  这就是传说中的线段树综合题,所有标记都有。

  注意一点,就是我的执行顺序是先add标记下传,然后才是set标记下传,但下传过程中set可以覆盖add。开始我一直WA,后来才发现了一个错误,就是我先执行的add,那么,如果当前结点上此时既有set又有add,那么只能说明add一定是在set之后执行的,不然执行set的时候add早已经下传,所以我可以考虑直接把add的值直接加在set上去,就可以避免有一部分add没有发挥作用。害得我调试了半个小时。

 //It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
#define RG register
const int MAXN = ;
int n,m,ql,qr;
LL val,ans,inf;
char ch[];
struct node{
int l,r;
LL minl,maxl,sum,add,set;
bool flag;
}a[MAXN*]; inline LL getint(){RG LL w=,q=; char c=getchar();while((c<'' || c>'') && c!='-') c=getchar(); if(c=='-') q=,c=getchar();while (c>='' && c<='') w=w*+c-'', c=getchar(); return q ? -w : w;} inline void update(RG int root){
RG int lc=root*,rc=lc+; a[root].maxl=max(a[lc].maxl,a[rc].maxl);
a[root].sum=a[lc].sum+a[rc].sum; a[root].minl=min(a[lc].minl,a[rc].minl);
} inline void build(RG int root,RG int l,RG int r){
a[root].l=l; a[root].r=r;
if(l==r) { a[root].minl=a[root].maxl=a[root].sum=getint(); return ; }
RG int mid=(l+r)/; RG int lc=root*,rc=lc+;
build(lc,l,mid); build(rc,mid+,r); update(root);
} inline void pushdown(int root,int l,int r){
if(!a[root].flag) return ; if(l==r) { a[root].flag=false; a[root].set=; return ; }
int lc=root*,rc=lc+; int mid=(l+r)/;
a[lc].set=a[rc].set=a[root].set; a[root].add=a[lc].add=a[rc].add=;
a[lc].maxl=a[rc].maxl=a[lc].minl=a[rc].minl=a[root].set;
a[lc].sum=(LL)(mid-l+)*a[root].set; a[rc].sum=(LL)(r-mid)*a[root].set; a[root].sum=a[lc].sum+a[rc].sum;
a[lc].flag=a[rc].flag=true;
a[root].set=; a[root].flag=false;
} inline void pushdown_add(RG int root,RG int l,RG int r){
if(l==r) { a[root].add=; return ; } if(a[root].add==) return ; if(a[root].flag){ a[root].set+=a[root].add; a[root].add=; return ; }//至关重要,因为add打在set的后面,这就意味着相当于我们可以把set设的值变大一点 RG int mid=(l+r)/; RG int lc=root*,rc=lc+; a[lc].add+=a[root].add; a[rc].add+=a[root].add;
a[lc].minl+=a[root].add; a[lc].maxl+=a[root].add; a[rc].minl+=a[root].add; a[rc].maxl+=a[root].add;
a[lc].sum+=a[root].add*(LL)(mid-l+); a[rc].sum+=a[root].add*(LL)(r-mid);
a[root].add=; a[root].sum=a[lc].sum+a[rc].sum;
} inline void add(RG int root,RG int l,RG int r){
pushdown_add(root,l,r); pushdown(root,l,r);
if(ql<=l && r<=qr) { a[root].add+=val; a[root].maxl+=val; a[root].minl+=val; a[root].sum+=val*(LL)(r-l+); return ; }
RG int mid=(l+r)/; RG int lc=root*,rc=lc+; if(ql<=mid) add(lc,l,mid); if(qr>mid) add(rc,mid+,r);
update(root);
} inline void update_set(RG int root,RG int l,RG int r){
if(ql<=l && r<=qr) { a[root].flag=true; a[root].minl=a[root].maxl=a[root].set=val; a[root].add=; a[root].sum=(LL)(r-l+)*val; return ; }
pushdown_add(root,l,r); pushdown(root,l,r);
RG int mid=(l+r)/;RG int lc=root*,rc=lc+;
if(ql<=mid) update_set(lc,l,mid); if(qr>mid) update_set(rc,mid+,r); update(root);
} inline void query_sum(RG int root,RG int l,RG int r){
pushdown_add(root,l,r); pushdown(root,l,r);
if(ql<=l && r<=qr){ ans+=a[root].sum; return ; }
RG int mid=(l+r)/; RG int lc=root*,rc=lc+;
if(ql<=mid) query_sum(lc,l,mid); if(qr>mid) query_sum(rc,mid+,r); update(root);
} inline void query_max(RG int root,RG int l,RG int r){
pushdown_add(root,l,r); pushdown(root,l,r);
if(ql<=l && r<=qr){ ans=max(a[root].maxl,ans); return ; }
RG int mid=(l+r)/; RG int lc=root*,rc=lc+;
if(ql<=mid) query_max(lc,l,mid); if(qr>mid) query_max(rc,mid+,r); update(root);
} inline void query_min(RG int root,RG int l,RG int r){
pushdown_add(root,l,r); pushdown(root,l,r);
if(ql<=l && r<=qr){ ans=min(a[root].minl,ans); return ; }
RG int mid=(l+r)/; RG int lc=root*,rc=lc+;
if(ql<=mid) query_min(lc,l,mid); if(qr>mid) query_min(rc,mid+,r); update(root);
} inline void work(){
n=getint(); m=getint(); build(,,n); inf=; for(RG int i=;i<=;i++) inf*=;
while(m--) {
scanf("%s",ch);
if(ch[]=='a') { ql=getint(); qr=getint(); val=getint(); add(,,n); }
else if(ch[]=='s' && ch[]=='e') { ql=getint(); qr=getint(); val=getint(); update_set(,,n); }
else if(ch[]=='s' && ch[]=='u') { ql=getint(); qr=getint(); ans=; query_sum(,,n); printf("%lld\n",ans); }
else if(ch[]=='m' && ch[]=='a') { ql=getint(); qr=getint(); ans=-inf; query_max(,,n); printf("%lld\n",ans); }
else{ ql=getint(); qr=getint(); ans=inf; query_min(,,n); printf("%lld\n",ans); }
}
} int main()
{
work();
return ;
}

codevs4927 线段树练习5的更多相关文章

  1. 分块试水--CODEVS4927 线段树练习5

    模板 #include<stdio.h> #include<algorithm> #include<string.h> #include<stdlib.h&g ...

  2. 【codevs4927】线段树练习

    题目大意:维护一个序列,支持区间加.区间染色.区间最值查询.区间和查询. 题解:对于区间赋值操作来说,维护一个赋值标记,注意,这里不能直接用赋值的值直接维护,因为不像加法标记,0 表示不用处理,这里 ...

  3. CSU 2151 集训难度【多标记线段树】

    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2151 Input 第一行三个数n,m,v0 表示有n名萌新和m次调整,初始时全部萌新的集训难度 ...

  4. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  5. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  6. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  7. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  8. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

  9. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

随机推荐

  1. 学员信息录入(StuInfoManager) 用分层实现(既MySchool后的一个案例)

    数据库 数据表名 Student 中文表名 学员信息表 字段显示 字段名 数据类型 字段大小 备注和说明 编号 stu_id int 主键,自增1 学生姓名 stu_name varchar 50 不 ...

  2. 关于tcpdump抓包一个很详细的介绍

    http://www.cnblogs.com/ggjucheng/archive/2012/01/14/2322659.html

  3. android studio 中的编码问题

    在 Android studio 中直接创建项目和导入其他项目都会有一个文件编码设定的问题,在 android studio (version 1.2.0)中设置文件的编码,只需要两步: 1.打开Se ...

  4. Java虚拟机工作原理详解 ( 二 )

    首先这里澄清两个概念:JVM实例和JVM执行引擎实例,JVM实例对应了一个独立运行的Java程序,而JVM执行引擎实例则对应了属于用户运行程序的线程:也就是JVM实例是进程级别,而执行引擎是线程级别的 ...

  5. linux下的缓存机制及清理buffer/cache/swap的方法梳理

    (1)缓存机制 为了提高文件系统性能,内核利用一部分物理内存分配出缓冲区,用于缓存系统操作和数据文件,当内核收到读写的请求时,内核先去缓存区找是否有请求的数据,有就直接返回,如果没有则通过驱动程序直接 ...

  6. React Native iOS环境搭建

    前段时间React Native for Android发布,感觉React Native会越来越多的公司开始研究.使用.所以周六也抽空搭建了iOS的开发环境,以便以后利用空闲的时间能够学习一下. 废 ...

  7. Elasticsearch 相关名词理解

    Cluster包含多个node,Indices不应该理解成动词索引,Indices可理解成关系数据库中的databases,Indices可包含多个Index,Index对应关系数据库中的databa ...

  8. C语言 const与指针

    //const与指针 #include<stdio.h> #include<stdlib.h> void main(){ ; ; const int *p; p = & ...

  9. IP+IDC-chinaz抓取

    #-*-coding:gbk-*- #code by anyun.org import urllib import re import time def getHtml(url): page = ur ...

  10. 为什么需要DTO(数据传输对象)

    DTO即数据传输对象.之前不明白有些框架中为什么要专门定义DTO来绑定表现层中的数据,为什么不能直接用实体模型呢,有了DTO同时还要维护DTO与Model之间的映射关系,多麻烦. 然后看了这篇文章中的 ...