P1253 [yLOI2018] 扶苏的问题
题面
给定一个长度为 \(n\) 的序列 \(a\),要求支持如下三个操作:
- 给定区间 \([l, r]\),将区间内每个数都修改为 \(x\)。
- 给定区间 \([l, r]\),将区间内每个数都加上 \(x\)。
- 给定区间 \([l, r]\),求区间内的最大值。
输入格式
第一行是两个整数,依次表示序列的长度 \(n\) 和操作的个数 \(q\)。
第二行有 \(n\) 个整数,第 \(i\) 个整数表示序列中的第 \(i\) 个数 \(a_i\)。
接下来 \(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\) 的操作,输出一行一个整数表示答案。
数据规模与约定
- 对于 \(10\%\) 的数据,\(n = q = 1\)。
- 对于 \(40\%\) 的数据,\(n, q \leq 10^3\)。
- 对于 \(50\%\) 的数据,\(0 \leq a_i, x \leq 10^4\)。
- 对于 \(60\%\) 的数据,\(op \neq 1\)。
- 对于 \(90\%\) 的数据,\(n, q \leq 10^5\)。
- 对于 \(100\%\) 的数据,\(1 \leq n, q \leq 10^6\),\(1 \leq l, r \leq n\),\(op \in \{1, 2, 3\}\),\(|a_i|, |x| \leq 10^9\)。
提示
请注意大量数据读入对程序效率造成的影响。
思路
这道题太坑了。
用线段树维护区间 \(\max\),以及区间赋值与区间加的 \(\text{lazy-tag}\)。
记得在赋值的时候清空 add
标记!(这个我 \(60\) 分咕了很久)。
代码
其实我觉得提示中的信息没有一点用。
#include <bits/stdc++.h>
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
#define int long long
using namespace std;
struct node{
int maxv,add,cov;
node(){
this->cov = LLONG_MIN;
this->add = 0;
}
} t[4000005];
int a[1000005];
int n,q;
inline void pushup(int i){
t[i].maxv=max(t[ls].maxv,t[rs].maxv);
}
void build(int i,int l,int r){
if(l==r){
t[i].maxv=a[l];
}
else{
build(ls,l,mid);
build(rs,mid+1,r);
pushup(i);
}
}
void pushdown(int i){
if(t[i].cov!=LLONG_MIN){
t[ls].maxv=t[rs].maxv=t[ls].cov=t[rs].cov=t[i].cov;
//t[ls].cov+=t[ls].add;
//t[rs].cov+=t[rs].add;
t[ls].add=t[rs].add=0;
t[i].cov=LLONG_MIN;
}
if(t[i].add){
t[ls].add+=t[i].add;
t[rs].add+=t[i].add;
t[ls].maxv+=t[i].add;
t[rs].maxv+=t[i].add;
t[i].add=0;
}
}
void add(int ql,int qr,int v,int i,int l,int r){
if(ql<=l&&r<=qr){
t[i].maxv+=v;
t[i].add+=v;
return;
}
pushdown(i);
if(ql<=mid){
add(ql,qr,v,ls,l,mid);
}
if(mid<qr){
add(ql,qr,v,rs,mid+1,r);
}
pushup(i);
}
void cover(int ql,int qr,int v,int i,int l,int r){
if(ql<=l&&r<=qr){
t[i].maxv=v;
t[i].cov=v;
t[i].add=0;
return;
}
pushdown(i);
if(ql<=mid){
cover(ql,qr,v,ls,l,mid);
}
if(mid<qr){
cover(ql,qr,v,rs,mid+1,r);
}
pushup(i);
}
int query(int ql,int qr,int i,int l,int r){
if(ql<=l&&r<=qr){
return t[i].maxv;
}
pushdown(i);
int result=LLONG_MIN;
if(ql<=mid){
result=max(result,query(ql,qr,ls,l,mid));
}
if(mid<qr){
result=max(result,query(ql,qr,rs,mid+1,r));
}
return result;
}
signed main(){
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,n);
while(q--){
int op,l,r,x;
cin>>op;
if(op==2){
cin>>l>>r>>x;
add(l,r,x,1,1,n);
}
if(op==1){
cin>>l>>r>>x;
cover(l,r,x,1,1,n);
}
if(op==3){
cin>>l>>r;
cout<<query(l,r,1,1,n)<<endl;
}
}
return 0;
}