题目描述 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. TP快捷函数

    U();创建URL地址 C();获取或设置系统变量信息 A();实例化控制器对象 R():实例化控制器对象且同时调用控制器里的某个方法 I();过滤表单提交的数据,代替$_POST

  2. javascript中的array对象属性及方法

    Array 对象 Array 对象用于在单个的变量中存储多个值. 创建 Array 对象的语法: new Array(); new Array(size); new Array(element0, e ...

  3. wireshark添加ip.id字段

    wireshark添加ip.id字段 为了在多个设备上追踪同一个数据包. 如果是同一个会话,则可以计算延迟, 如sta和应用服务器慢,这种问题,可以根据这个加上ip.id追踪数据到哪里慢了.    

  4. GO To Definition的背后操作【VS2015 C#】

    使用VS开发U3D项目时,去察看某个变量的声明,比如某组件的gameObject变量,会看到如下代码 一看似乎有点晕,这代码什么意思啊,就一个 public GameObject gameObject ...

  5. IBatisNet基础组件

    DomSqlMapBuilder DomSqlMapBuilder,其作用是根据配置文件创建SqlMap实例.可以通过这个组件从Stream, Uri, FileInfo, or XmlDocumen ...

  6. Linux第二次报告20135221

    学习计时:共xxx小时 读书: 代码: 作业: 博客: 一.学习目标 1. 熟悉Linux系统下的开发环境   2. 熟悉vi的基本操作   3. 熟悉gcc编译器的基本原理   4. 熟练使用gcc ...

  7. JS模拟Alert与Confirm对话框

    这2个例子都是用原生JS写的,主要是用JS拼接了界面,并未做过多的事件监听.,样式用了Css3的一些特性. 调用方式则为: //Alert Alert.show('我警告你哦~'); //Confir ...

  8. MVC5 + EF6 + Bootstrap3 (9) HtmlHelper用法大全(下)

    文章来源:Slark.NET-博客园 http://www.cnblogs.com/slark/p/mvc5-ef6-bs3-get-started-httphelper-part2.html 上一节 ...

  9. [C/C++基础] C语言常用函数memset的使用方法

    函数声明:void *memset(void *s, int ch, size_t n); 用途:为一段内存的每一个字节都赋予ch所代表的值,该值采用ASCII编码. 所属函数库:<memory ...

  10. 如何使用Iveely的数据存储引擎 Iveely Database

    Iveely 数据存储引擎是为Iveely 搜索引擎提供数据存储的机制. 适用于:频繁数据插入.数据读取.数据更改或者删除数据不适合Iveely Database,存储结构是按照搜索引擎数据存储要求( ...