【洛谷 P1253】扶苏的问题
今天还是抽了点时间写题
P1253 扶苏的问题
题目描述
给定一个长度为 \(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\) 的操作,输出一行一个整数表示答案。
输入输出样例 #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
说明/提示
数据规模与约定
- 对于 \(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\)。
提示
请注意大量数据读入对程序效率造成的影响。
解法&&个人感想
这题要求我们打上两个标记,第一个是覆盖标记,第二个是加法标记,这很容易看出来
然后,细致的pushdown操作,需要我们思考一下
因为,当某个区间被覆盖之后,由于延迟标记的关系,可能紧接着又有加法操作出现,此时,在pushdown的时候,我们就有必要慎重考虑一下要怎么操作了,在这道题里,确实需要深思熟虑,我也调了很久,就是因为上面说的,所以子树们必须继承根节点的两个懒标记,这就是精髓所在
直接放代码吧,我觉得能想出来的,多调调就好了,不想多解释
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define lowbit(x) (x&(-x))
#define maxn 1000005
using namespace std;
const ll INF=1e18+5;
struct SegmentTree{
ll l,r,fz,add,ma;
bool iffz;
}tree[4*maxn];
ll ma[maxn];
ll n,m,op,x,y,k;
void build(ll x,ll l,ll r){
tree[x].l=l;tree[x].r=r;
if(tree[x].l==tree[x].r){
tree[x].ma=ma[l];
return ;
}
ll mid=(tree[x].l+tree[x].r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
tree[x].ma=max(tree[x*2].ma,tree[x*2+1].ma);
return ;
}
void pushdown(ll x){
if(tree[x].iffz){
tree[x*2].iffz=true;
tree[x*2+1].iffz=true;
tree[x*2].fz=tree[x].fz;
tree[x*2+1].fz=tree[x].fz;
tree[x*2].ma=tree[x].fz+tree[x].add;
tree[x*2+1].ma=tree[x].fz+tree[x].add;
tree[x*2].add=tree[x].add;tree[x*2+1].add=tree[x].add;
tree[x].add=0;
tree[x].fz=0;
tree[x].iffz=false;
return ;
}
else if(tree[x].add){
tree[x*2].add+=tree[x].add;
tree[x*2+1].add+=tree[x].add;
tree[x*2].ma+=tree[x].add;
tree[x*2+1].ma+=tree[x].add;
tree[x].add=0;
return ;
}
return ;
}
void change_1(ll x,ll l,ll r,ll k){
if(l<=tree[x].l&&tree[x].r<=r){
tree[x].add=0;
tree[x].iffz=true;
tree[x].fz=k;
tree[x].ma=k;
return ;
}
pushdown(x);
ll mid=(tree[x].l+tree[x].r)/2;
if(l<=mid) change_1(x*2,l,r,k);
if(r>mid) change_1(x*2+1,l,r,k);
tree[x].ma=max(tree[x*2].ma,tree[x*2+1].ma);
return ;
}
void change_2(ll x,ll l,ll r,ll k){
if(l<=tree[x].l&&tree[x].r<=r){
tree[x].add+=k;
tree[x].ma+=k;
return ;
}
pushdown(x);
ll mid=(tree[x].l+tree[x].r)/2;
if(l<=mid) change_2(x*2,l,r,k);
if(r>mid) change_2(x*2+1,l,r,k);
tree[x].ma=max(tree[x*2].ma,tree[x*2+1].ma);
return ;
}
ll query(ll x,ll l,ll r){
if(l<=tree[x].l&&tree[x].r<=r) return tree[x].ma;
ll mid=(tree[x].l+tree[x].r)/2;
pushdown(x);
ll ans=-INF;
if(l<=mid) ans=max(ans,query(x*2,l,r));
if(r>mid) ans=max(ans,query(x*2+1,l,r));
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&ma[i]);
}
for(int i=1;i<=4*n;i++){
tree[i].ma=-INF;
tree[i].iffz=false;
}
build(1,1,n);
for(int i=1;i<=m;i++){
scanf("%lld",&op);
if(op==1){
scanf("%lld%lld%lld",&x,&y,&k);
change_1(1,x,y,k);
}
else if(op==2){
scanf("%lld%lld%lld",&x,&y,&k);
change_2(1,x,y,k);
}
else{
scanf("%lld%lld",&x,&y);
ll ans=query(1,x,y);
printf("%lld\n",ans);
}
}
system("pause");
return 0;
}
后半学期,也请各位继续关注:
《我的青春线代物语果然有问题》
《高数女主养成计划》
《程设の旅》
《青春猪头少年不会梦到多智能体吃豆人》
《某Linux的开源软件》
《Charlotte太空探索》
还有——
《我的算法竞赛不可能这么可爱》
本期到此结束!

浙公网安备 33010602011771号