华丽的序列题解
华丽的序列题解
题目描述
给定一个长度为 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;
}