P4243 [JSOI2009]等差数列
这个题可以用差分做
因为等差数列的性质就是差相等
我们维护这些东西
当前区间的左端点的数值 ->vl
当前区间的右端点的数值 -> vr
当前区间如果左右端点都不选有多少个等差数列 -> s[0]
当前区间如果只选左端点有多少个等差数列 -> s[1]
当前区间如果只选右端点有多少个等差数列 -> s[2]
当前区间如果左右端点都选有多少个等差数列 -> s[3]
就会发现
区间可以这么合并
vl[o]=vl[l];vr[o]=vr[r];
v
l
[
o
]
=
v
l
[
l
]
;
v
r
[
o
]
=
v
r
[
r
]
;
s[o][0]=minn(s[l][1]+s[r][2]−(vr[l]==vl[r]),s[l][0]+s[r][2],s[r][0]+s[l][1]);
s
[
o
]
[
0
]
=
m
i
n
n
(
s
[
l
]
[
1
]
+
s
[
r
]
[
2
]
−
(
v
r
[
l
]
==
v
l
[
r
]
)
,
s
[
l
]
[
0
]
+
s
[
r
]
[
2
]
,
s
[
r
]
[
0
]
+
s
[
l
]
[
1
]
)
;
s[o][1]=minn(s[l][1]+s[r][3]−(vr[l]==vl[r]),s[l][0]+s[r][3],s[r][1]+s[l][1]);
s
[
o
]
[
1
]
=
m
i
n
n
(
s
[
l
]
[
1
]
+
s
[
r
]
[
3
]
−
(
v
r
[
l
]
==
v
l
[
r
]
)
,
s
[
l
]
[
0
]
+
s
[
r
]
[
3
]
,
s
[
r
]
[
1
]
+
s
[
l
]
[
1
]
)
;
s[o][2]=minn(s[l][3]+s[r][2]−(vr[l]==vl[r]),s[l][3]+s[r][0],s[r][2]+s[l][2]);
s
[
o
]
[
2
]
=
m
i
n
n
(
s
[
l
]
[
3
]
+
s
[
r
]
[
2
]
−
(
v
r
[
l
]
==
v
l
[
r
]
)
,
s
[
l
]
[
3
]
+
s
[
r
]
[
0
]
,
s
[
r
]
[
2
]
+
s
[
l
]
[
2
]
)
;
s[o][3]=minn(s[l][3]+s[r][3]−(vr[l]==vl[r]),s[l][2]+s[r][3],s[r][1]+s[l][3]);
s
[
o
]
[
3
]
=
m
i
n
n
(
s
[
l
]
[
3
]
+
s
[
r
]
[
3
]
−
(
v
r
[
l
]
==
v
l
[
r
]
)
,
s
[
l
]
[
2
]
+
s
[
r
]
[
3
]
,
s
[
r
]
[
1
]
+
s
[
l
]
[
3
]
)
;
就OK了
查询时要多开些点,保留合并的信息
#include<cstdio>
#include<iostream>
#define ls o<<1
#define rs o<<1|1
using namespace std;
const int M=1000000;
int n,q,a[M],cnt,maxn;
struct SIG{
int vl[4*M],vr[4*M],s[4*M][4],add[4*M];
int minn(int y,int z,int w){
return min(min(w,y),z);
}
void update(int o,int l,int r){
vl[o]=vl[l];vr[o]=vr[r];
s[o][0]=minn(s[l][1]+s[r][2]-(vr[l]==vl[r]),s[l][0]+s[r][2],s[r][0]+s[l][1]);
s[o][1]=minn(s[l][1]+s[r][3]-(vr[l]==vl[r]),s[l][0]+s[r][3],s[r][1]+s[l][1]);
s[o][2]=minn(s[l][3]+s[r][2]-(vr[l]==vl[r]),s[l][3]+s[r][0],s[r][2]+s[l][2]);
s[o][3]=minn(s[l][3]+s[r][3]-(vr[l]==vl[r]),s[l][2]+s[r][3],s[r][1]+s[l][3]);
}
void built(int o,int l,int r){
if(l==r) {
vl[o]=a[l];vr[o]=a[l];
add[o]=0;s[o][1]=s[o][2]=s[o][3]=1;
s[o][0]=0;return ;
}
int mid=(l+r)>>1;
built(ls,l,mid);built(rs,mid+1,r);cnt=max(cnt,rs);maxn=cnt;
add[o]=0;update(o,ls,rs);
}
void pushdown(int o){
if(add[o]){
add[ls]+=add[o];add[rs]+=add[o];
vl[ls]+=add[o];vl[rs]+=add[o];
vr[ls]+=add[o];vr[rs]+=add[o];
add[o]=0;
}
}
void modify(int o,int l,int r,int ql,int qr,int ins){
if(l>qr||r<ql) return ;
if(l>=ql&&r<=qr) {
vl[o]+=ins;vr[o]+=ins;
add[o]+=ins; return ;
}
pushdown(o);int mid=(l+r)>>1;
modify(ls,l,mid,ql,qr,ins);
modify(rs,mid+1,r,ql,qr,ins);
update(o,ls,rs);
}
int query(int o,int l,int r,int ql,int qr){
if(l>qr||r<ql) return 0;
if(l>=ql&&r<=qr) return o;
int mid=(l+r)>>1;pushdown(o);
int t1=query(ls,l,mid,ql,qr);
int t2=query(rs,mid+1,r,ql,qr);
if(t1&&t2)update(++cnt,t1,t2);
if(t1&&t2) return cnt;
else return t1?t1:t2;
}
}T;
int main(){scanf("%d",&n);cnt=n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++) a[i]=a[i+1]-a[i];
T.built(1,1,n-1);scanf("%d",&q);
while(q--){char s[10];int l,r,x,y;
scanf("%s%d%d",s,&l,&r);
if(s[0]=='A'){scanf("%d%d",&x,&y);
if(l!=1) T.modify(1,1,n-1,l-1,l-1,x);
if(r!=n) T.modify(1,1,n-1,r,r,-(x+y*(r-l)));
if(l!=r) T.modify(1,1,n-1,l,r-1,y);
}
else{if(l==r) puts("1");
else cnt=maxn,printf("%d\n",T.s[T.query(1,1,n-1,l,r-1)][3]);
}
}
}