codevs4927 线段树练习5
有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]的最小值
第一行两个整数n,m,第二行n个整数表示这n个数的初始值
接下来m行操作,同题目描述
对于所有的sum、max、min询问,一行输出一个答案
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
49
11
4
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的更多相关文章
- 分块试水--CODEVS4927 线段树练习5
模板 #include<stdio.h> #include<algorithm> #include<string.h> #include<stdlib.h&g ...
- 【codevs4927】线段树练习
题目大意:维护一个序列,支持区间加.区间染色.区间最值查询.区间和查询. 题解:对于区间赋值操作来说,维护一个赋值标记,注意,这里不能直接用赋值的值直接维护,因为不像加法标记,0 表示不用处理,这里 ...
- CSU 2151 集训难度【多标记线段树】
http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2151 Input 第一行三个数n,m,v0 表示有n名萌新和m次调整,初始时全部萌新的集训难度 ...
- bzoj3932--可持久化线段树
题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...
- codevs 1082 线段树练习 3(区间维护)
codevs 1082 线段树练习 3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...
- codevs 1576 最长上升子序列的线段树优化
题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...
- codevs 1080 线段树点修改
先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...
- codevs 1082 线段树区间求和
codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...
- PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树
#44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...
随机推荐
- AC日记——产生数 codevs 1009 (弗洛伊德)(组合数学)
1009 产生数 2002年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Descriptio ...
- C++ 箭头-> 双冒号:: 点号.操作符区别
点 (.) 如果变量是一个对象或者对象引用,则用它来访问对象成员. 箭头( ->) 如果变量是一个对象指针,则用它来访问对象成员. 双冒号 (::) 如果操作目标是一个具有名空间的标识符,则用它 ...
- 了解了这些才能开始发挥jQuery的威力(转)
链接:http://www.cnblogs.com/dolphinX/archive/2013/10/08/3347677.html 由于当前jQuery如此的如雷贯耳,相信不用介绍什么是jQuery ...
- Use CLR Profiler
Use CLR Profiler 第一次翻译对我而言比较长的E文,有很多不足之处,请见谅.(个人的习惯GC又做了名词又做了名词) 原文:http://msdn.microsoft.com/en-us/ ...
- react native 底部按钮切换
在react native 中底部按钮的切换 主要的是运用的是<TabBarNavigator/>这个组件,具体的代码实现如下: render() { return ( <T ...
- 在c++程序中执行DOS命令
转自博客:http://blog.csdn.net/ypist/article/details/8485049 #1,system()方式 在C盘根目录下新建文件夹,名称为12: system(&qu ...
- python字符串str和字节数组相互转化
b = b"Hello, world!" # bytes object s = "Hello, world!" # str object print('str ...
- 问卷调查——答卷
1.你对自己的未来有什么规划?做了哪些准备?答:对未来的规划,就是像大多数人一样,在学校里有一个好的成绩,掌握扎实的专业基础,然后在国考上得到一个好成绩,得到一个好的工作机会,然后努力工作.目标很简单 ...
- PM2实用入门指南
简介 PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控.自动重启.负载均衡等,而且使用非常简单. 下面就对PM2进行入门性的介绍,基本涵盖了PM2的常用的功能和 ...
- IT男的”幸福”生活"续4
翻来翻去,总是睡不觉.大脑口一堆问题.一个又冒出一个,没完没了.明天该怎样去进行下一步呢.. ….. 夜一下子深黑很多,窗外的公路,时而有货车通过,动不动按喇叭,而我住在二楼,真它的吵.也许她住在五楼 ...