1. 程式人生 > 其它 >華麗的序列題解

華麗的序列題解

華麗的序列題解

題目描述

給定一個長度為 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;
}