【题解】P11334 [NOISG 2020 Finals] Progression
P11334 [NOISG 2020 Finals] Progression
题意
给定长度为 \(n\) 的序列,进行 \(m\) 次操作或询问:
- 区间加等差数列
- 区间设等差数列
- 查询区间内最长等差数列长度
题解
知识点:线段树,差分。
启发:
-
原数组转差分数组方便操作。
-
一种信息合并的技巧。
难写又难调。
看到一堆等差,果断先将原数组差分。
那么 \([l,r]\) 的最长等差数列长度其实就是差分数组的 \([l+1,r]\) 的最长颜色段长度加一。
在差分数组上,\([l,r]\) 加等差数列就变成了区间加问题,而设等差数列则是区间推平,这两个操作用线段树可以轻易实现,不过千万不能忘了第 \((r+1)\) 位置也要修改。
现在考虑 push_up 的实现,对每个结点分别维护从左端点开始、从右端点开始以及整体的最长颜色段,那么合并的方法就很显然了,对着维护区间最大子段和的方法照葫芦画瓢即可。
整体思路就这么简单,这题主要是代码较为难写。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 302505
#define int long long
int n,m,a[N];
struct SEG{
#define mid ((l+r)>>1)
int add[N<<2],col[N<<2];
bitset<N<<2>cc;
struct node{
pr p,l,r;
int len,sum;
node(){
len=0;
p=l=r={0,0};
}
}tr[N<<2];
inline node un(node x,node y){
node g;
g.l=x.l;
g.r=y.r;
g.p=max(x.p,y.p);
g.len=x.len+y.len;
g.sum=x.sum+y.sum;
if(x.r.se==y.l.se){
g.p=max(g.p,{x.r.fi+y.l.fi,x.r.se});
}
if(x.l.fi==x.len&&x.l.se==y.l.se){
g.l=max(g.l,{x.l.fi+y.l.fi,x.l.se});
}
if(y.r.fi==y.len&&y.r.se==x.r.se){
g.r=max(g.r,{y.r.fi+x.r.fi,y.r.se});
}
g.p=max({g.p,g.l,g.r});
return g;
}
inline void t_add(int k,int l,int r,int d){
add[k]+=d;
tr[k].sum+=d*(r-l+1);
tr[k].p.se+=d;
tr[k].l.se+=d;
tr[k].r.se+=d;
}
inline void t_col(int k,int l,int r,int d){
add[k]=0;
col[k]=d;
cc[k]=1;
tr[k].sum=d*(r-l+1);
tr[k].p=tr[k].l=tr[k].r={r-l+1,d};
}
inline void pd(int k,int l,int r){
if(cc[k]){
t_col(k*2,l,mid,col[k]);
t_col(k*2+1,mid+1,r,col[k]);
col[k]=0;
cc[k]=0;
}
if(add[k]){
t_add(k*2,l,mid,add[k]);
t_add(k*2+1,mid+1,r,add[k]);
add[k]=0;
}
}
inline void build(int k,int l,int r){
add[k]=0;
col[k]=0;
cc[k]=0;
if(l==r){
tr[k].p=tr[k].l=tr[k].r={1,a[l]};
tr[k].len=1;
tr[k].sum=a[l];
return;
}
build(k*2,l,mid);
build(k*2+1,mid+1,r);
tr[k]=un(tr[k*2],tr[k*2+1]);
}
inline void upd_add(int L,int R,int k,int l,int r,int d){
if(L>R){
return;
}
if(L<=l&&R>=r){
t_add(k,l,r,d);
return;
}
pd(k,l,r);
if(L<=mid){
upd_add(L,R,k*2,l,mid,d);
}
if(R>mid){
upd_add(L,R,k*2+1,mid+1,r,d);
}
tr[k]=un(tr[k*2],tr[k*2+1]);
}
inline void upd_col(int L,int R,int k,int l,int r,int d){
if(L>R){
return;
}
if(L<=l&&R>=r){
t_col(k,l,r,d);
return;
}
pd(k,l,r);
if(L<=mid){
upd_col(L,R,k*2,l,mid,d);
}
if(R>mid){
upd_col(L,R,k*2+1,mid+1,r,d);
}
tr[k]=un(tr[k*2],tr[k*2+1]);
}
inline node ask(int L,int R,int k,int l,int r){
if(L>R){
node sb;
return sb;
}
if(L<=l&&R>=r){
return tr[k];
}
pd(k,l,r);
node ls,rs;
if(L<=mid){
ls=ask(L,R,k*2,l,mid);
}
if(R>mid){
rs=ask(L,R,k*2+1,mid+1,r);
}
return un(ls,rs);
}
inline int sum(int L,int R,int k,int l,int r){
if(L>R){
return 0;
}
if(L<=l&&R>=r){
return tr[k].sum;
}
pd(k,l,r);
int ans=0;
if(L<=mid){
ans+=sum(L,R,k*2,l,mid);
}
if(R>mid){
ans+=sum(L,R,k*2+1,mid+1,r);
}
return ans;
}
#undef mid
}t;
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,n){
cin>>a[i];
}
per(i,1,n){
a[i]-=a[i-1];
}
t.build(1,1,n);
rep(i,1,m){
int op,l,r,s,c;
cin>>op>>l>>r;
if(op==1){
cin>>s>>c;
int pre=0;
if(r+1<=n){
pre=t.sum(1,r+1,1,1,n);
}
t.upd_add(l,l,1,1,n,s);
t.upd_add(l+1,r,1,1,n,c);
if(r+1<=n){
t.upd_col(r+1,r+1,1,1,n,pre-t.sum(1,r,1,1,n));
}
}
if(op==2){
cin>>s>>c;
int pre=0;
if(r+1<=n){
pre=t.sum(1,r+1,1,1,n);
}
int tmp=s-t.sum(1,l-1,1,1,n);
t.upd_col(l,l,1,1,n,tmp);
t.upd_col(l+1,r,1,1,n,c);
if(r+1<=n){
t.upd_col(r+1,r+1,1,1,n,pre-t.sum(1,r,1,1,n));
}
}
if(op==3){
cout<<t.ask(l+1,r,1,1,n).p.fi+1<<"\n";
}
}
return 0;
}

浙公网安备 33010602011771号