扶苏的问题

[yLOI2018] 扶苏的问题

题目描述

给定一个长度为 n 的序列 a,要求支持如下三个操作:

  1. 给定区间 [l,r],将区间内每个数都修改为 x
  2. 给定区间 [l,r],将区间内每个数都加上 x
  3. 给定区间 [l,r],求区间内的最大值。

输入格式

第一行是两个整数,依次表示序列的长度 n 和操作的个数 q
第二行有 n 个整数,第 i 个整数表示序列中的第 i 个数 ai
接下来 q 行,每行表示一个操作。每行首先有一个整数 op,表示操作的类型。

  • op=1,则接下来有三个整数 l,r,x,表示将区间 [l,r] 内的每个数都修改为 x
  • op=2,则接下来有三个整数 l,r,x,表示将区间 [l,r] 内的每个数都加上 x
  • op=3,则接下来有两个整数 l,r,表示查询区间 [l,r] 内的最大值。

输出格式

对于每个 op=3 的操作,输出一行一个整数表示答案。

样例 #1

样例输入 #1

6 6
1 1 4 5 1 4
1 1 2 6
2 3 4 2
3 1 4
3 2 3
1 1 6 -1
3 1 6

样例输出 #1

7
6
-1

样例 #2

样例输入 #2

4 4
10 4 -3 -7
1 1 3 0
2 3 4 -4
1 2 4 -9
3 1 4

样例输出 #2

0

提示

数据规模与约定

  • 对于 100% 的数据,1n,q1061l,rnop{1,2,3}|ai|,|x|109

思路

这是一道线段树的模板题。需要求出区间内的最大值。可以使用两个懒标记,一个寸增加的,一个存修改的。但是有一个细节,很容易错,就是在打懒标记的时候,如果你打了一个修改的懒标记,前面打的加标记就没用了,要清空!

代码

#include<cstdio>
const long long INF=0x7fffffffffffffff;
#define int long long 
template<typename Tp>Tp max(Tp a,Tp b){
	return a>b?a:b;
} 
template<typename Tp,const int Size>class LineTree{
	private:
		struct node{
			int l,r;
			Tp add=0,set=-INF,data=-INF;
		};
		node t[Size<<3];
		int LeftSon(int p){
			return p<<1; 
		}
		int RightSon(int p){
			return (p<<1)|1;
		}
		void make_add(int p,Tp data){
			t[p].data+=data;
			t[p].add+=data;
		}
		void make_set(int p,Tp data){
			t[p].data=data;
			t[p].set=data;
			t[p].add=0;//清空加标记
		}
		void push_up(int p){
			t[p].data=max(t[LeftSon(p)].data,t[RightSon(p)].data);
		}
		void push_down(int p){
			if(t[p].set!=-INF){
				make_set(LeftSon(p),t[p].set);
				make_set(RightSon(p),t[p].set);
				t[p].set=-INF;
			}	
			if(t[p].add!=0){
				make_add(LeftSon(p),t[p].add);
				make_add(RightSon(p),t[p].add);
				t[p].add=0;
			}
		} 
	public:
		void build(int p,int l,int r,Tp a[]){
			t[p].l=l,t[p].r=r;
			if(l==r){t[p].data=a[l];return;}
			int mid=(l+r)>>1;
			build(LeftSon(p),l,mid,a);
			build(RightSon(p),mid+1,r,a);
			push_up(p);
		}
		void update_add(int p,int l,int r,Tp data){
			if(l<=t[p].l&&t[p].r<=r){
				make_add(p,data);
				return;
			}	
			push_down(p);
			if(t[LeftSon(p)].r>=l)update_add(LeftSon(p),l,r,data);
			if(t[RightSon(p)].l<=r)update_add(RightSon(p),l,r,data);
			push_up(p);
		} 
		void update_set(int p,int l,int r,Tp data){
			if(l<=t[p].l&&t[p].r<=r){
				make_set(p,data);
				return;
			}
			push_down(p);
			if(t[LeftSon(p)].r>=l)update_set(LeftSon(p),l,r,data);
			if(t[RightSon(p)].l<=r)update_set(RightSon(p),l,r,data);
			push_up(p);
		}
		Tp ask(int p,int l,int r){
			if(l<=t[p].l&&t[p].r<=r){return t[p].data;}
			push_down(p);
			Tp ret=-INF;
			if(t[LeftSon(p)].r>=l)ret=max(ret,ask(LeftSon(p),l,r));
			if(t[RightSon(p)].l<=r)ret=max(ret,ask(RightSon(p),l,r));
			return ret;
		}
};
LineTree<long long,1000001>tree;
long long a[1000001];
long long n,q;
signed main(){
	scanf("%lld%lld",&n,&q);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	tree.build(1,1,n,a);
	for(int i=1;i<=q;i++){
		long long op,l,r;
		scanf("%lld%lld%lld",&op,&l,&r);
		if(op==1){
			long long x;
			scanf("%lld",&x);
			tree.update_set(1,l,r,x);
		}else if(op==2){
			long long x;
			scanf("%lld",&x);
			tree.update_add(1,l,r,x);
		}else{
			printf("%lld\n",tree.ask(1,l,r));
		}
	}
	return 0;
}
posted @   maniubi  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示