华丽的序列题解

华丽的序列题解

题目描述

给定一个长度为 nn 的序列,序列上第 ii 个数为 aiai,有 QQ 次操作:
1.给定l,r,x,ai修改为min(ai,x),i∈[l,r]给定l,r,x,ai修改为min(ai,x),i∈[l,r]
2.给定l,r,询问max(ai),i∈[l,r]给定l,r,询问max(ai),i∈[l,r]
3.给定l,r,询问[l,r]之间所有ai的和给定l,r,询问[l,r]之间所有ai的和
输入格式

每次输入有多组数据,首先第一行一个整数TT,表示测试的个数。
在每次测试中都另起一行有两个整数n,mn,m。
接下来一行有nn个整数表示该序列。
接下来mm行表示所有操作,每次操作的第一个数typetype表示操作的类型,题目描述中的操作按顺序分别对应type=0,1,2type=0,1,2。 剩下的见题目描述即可。
输出格式

对每次询问一行一个整数表示答案。
样例
输入样例

1
5 5
1 2 3 4 5
1 1 5
2 1 5
0 3 5 3
1 1 5
2 1 5

输出样例

5
15
3
12

样例解释
数据范围与提示

n,Q≤106,T≤10n,Q≤106,T≤10
保证所有的aiai不超过231231。	

没链接,放题面好了。

这道题是一类线段树的例题,好像有个专门的名字忘了基本上都是修改大于k的或者小于k的,思路都一样废话或者拐弯抹角的,这道题还是比较裸的。


题解

首先

对于操作3用线段树维护一个区间和,然后就是要在操作1和操作2的过程中想办法保证线段树合法。

我们先来考虑操作2,我们只需要在线段树中维护一个最大值,在进行修改时区间修改的过程中维护区间和即可具体为:

t[id].sum=(t[id].r-t[id].l+1)*t[id].maxx;
t[id].lazy=t[id].maxx;

接着是本题唯一的难点操作1,其实略微的处理一下即可,我们在维护最大值的同时维护一个次大值和最大值的数量,当当前询问的区间被包含并且a小于最大值但是大于次大值时修改最大值,并且注意一个技巧无论何时当a大于当前区间的最大值跳出即可,因为区间中的元素一个也不会被修改记得开longlong

标程

#include<bits/stdc++.h>
using namespace std;
const int MN=1e6+100;
const int inf=0x3f3f3f3f;
typedef long long ll;
int T,n,m;
inline void write(ll x){
	if(x<0)putchar('-'),x=~x+1;
	if(x>9)write(x/10);putchar(x%10+'0');
}
struct node{
	int l,r;
	ll maxx,smx,cmx,sum;
}t[MN<<2];

inline void pushup(int id){
	int l(id<<1),r(id<<1|1);
	if(t[l].maxx>t[r].maxx){
		t[id].maxx=t[l].maxx;
		t[id].cmx=t[l].cmx;
		t[id].smx=max(t[l].smx,t[r].maxx);
	}
	else if(t[r].maxx>t[l].maxx){
		t[id].maxx=t[r].maxx;
		t[id].cmx=t[r].cmx;
		t[id].smx=max(t[r].smx,t[l].maxx);
	}
	else{
		t[id].maxx=t[l].maxx;
		t[id].cmx=t[l].cmx+t[r].cmx;
		t[id].smx=max(t[l].smx,t[r].smx);
	}
	t[id].sum=t[l].sum+t[r].sum;
}

inline void puttag(int id,ll v){
	if(t[id].maxx<=v)return;
	t[id].sum-=t[id].cmx*(t[id].maxx-v);
	t[id].maxx=v;
}

inline void pushdown(int id){
	puttag(id<<1,t[id].maxx),puttag(id<<1|1,t[id].maxx);
}

inline void build(int id,int l,int r){
	t[id].l=l,t[id].r=r;
	if(l==r){
		ll x;
		scanf("%lld",&x);
		t[id].maxx=t[id].sum=x;
		t[id].cmx=1;
		t[id].smx=-1;
		return;
	}
	int mid(l+r>>1);
	build(id<<1,l,mid),build(id<<1|1,mid+1,r);
	pushup(id);
}

inline void change(int id,int l,int r,ll k){
	if(t[id].maxx<=k)return;
	if(t[id].l>=l&&t[id].r<=r&&t[id].smx<k){
		puttag(id,k);
		return;
	}
	int mid(t[id].l+t[id].r>>1);
	pushdown(id);
	if(l<=mid)change(id<<1,l,r,k);
	if(r>=mid+1)change(id<<1|1,l,r,k);
	pushup(id);
}

inline ll get_sum(int id,int l,int r){
	if(t[id].l>=l&&t[id].r<=r){
		return t[id].sum;
	}
	int mid(t[id].l+t[id].r>>1);
	ll ans=0;
	pushdown(id);
	if(l<=mid)ans+=get_sum(id<<1,l,r);
	if(r>=mid+1)ans+=get_sum(id<<1|1,l,r);
	return ans;
}

inline ll get_max(int id,int l,int r){
	if(t[id].l>=l&&t[id].r<=r){
		return t[id].maxx;
	}
	int mid(t[id].l+t[id].r>>1);
	ll ans=-inf;
	pushdown(id);
	if(l<=mid)ans=max(ans,get_max(id<<1,l,r));
	if(r>=mid+1)ans=max(get_max(id<<1|1,l,r),ans);
	return ans;
}

signed main(){
	//freopen("gorgeoussequence.in","r",stdin);
	//freopen("gorgeoussequence.out","w",stdout);
	scanf("%d",&T);
	while(T--){
		memset(t,0,sizeof(t));
		scanf("%d%d",&n,&m);
		build(1,1,n);
		int type,l,r;
		ll x;
		for(int i=1;i<=m;++i){
			scanf("%d",&type);
			if(type==0){
				scanf("%d%d%lld",&l,&r,&x);
				change(1,l,r,x);
			}
			else if(type==1){
				scanf("%d%d",&l,&r);
				write(get_max(1,l,r));
				putchar('\n');
			}
			else{
				scanf("%d%d",&l,&r);
				write(get_sum(1,l,r));
				putchar('\n');
			}
		}
	}
	return 0;
}
posted @ 2021-08-04 17:56  fanner_rick  阅读(70)  评论(0)    收藏  举报