luogu P4243 [JSOI2009]等差数列 题解
前言:
这题真ex。。。

强烈谴责在题解里面放毒瘤题链接的屑出题人!
👴 吐 🌶️
解析:
这题分成两步走。
首先,既然题目中的修改操作是区间加等差数列,那么就容易想到在差分数组上进行操作。
然后就是相当恶心的查询。
转化到差分数组上,相信会有一部分小朋友会向我一样,傻乎乎的以为就是求一个区间极大相同连续段个数。。。
其实我是联想到了这个题。。虽说线段树维护的思路是相似的,但是显然这道黑题比那个树剖难维护的多。。。
回到这个题。刚才说到,求区间极大相同连续段个数其实是不行的。
因为可以发现下面的数组:
3,4,6,9
差分以后是这个值:
3,1,2,3
算极大相同连续段个数的话,就可以发现,得出的答案是4。
但其实答案是2。
错误原因是,假如差分数组中的某个极大相同连续段长度是1的话,它对应的是原序列的两个数,比如是a[i],a[i+1]。假如下一个大相同连续段的长度还是1,那它对应的就是原序列的a[i+1]和a[i+2]。
于是a[i+1]就被算了两遍。
那怎么处理呢?
直接说线段树的维护方法了。
struct node{
int val,lval,rval,lc,rc,lrval;
};
struct Segment_tree{
node x;
int lazy;
}tree[maxn<<2];
上面的node结构体维护的是某个区间[l,r]的信息。
val表示区间[l,r]最少能划分成几段,lval表示区间(l,r]最少能划分成几段(即不算l),rval表示区间[l,r)最少能划分成几段(即不算r),lrval表示区间(l,r)最少能划分成几段(即不算l和r)。
lc表示[l,r]的最左端点的值,rc表示[l,r]的最右端点的值。
lazy即区间加和标记。
那就有柿子(以更新val为例):
tree[rt].x.val=tree[rt<<1].x.val+tree[rt<<1|1].x.val-(tree[rt<<1].x.rc==tree[rt<<1|1].x.lc);
//即尝试把左右的儿子区间连起来。
tree[rt].x.val=min(tree[rt].x.val,min(tree[rt<<1].x.rval+tree[rt<<1|1].x.val,tree[rt<<1].x.val+tree[rt<<1|1].x.lval));
//即把左右儿子区间断开,分中间点算到左边和中间点算到右边的两种情况
//三种情况取min即可。
然后,就可以维护了。。。。
当然,代码有亿点毒瘤...
亿点毒瘤的代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=100000+10;
int read(){
int w=0,x=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') x=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=(w<<1)+(w<<3)+(ch^48);
ch=getchar();
}
return w*x;
}
int n,q;
int c[maxn];
struct node{
int val,lval,rval,lc,rc,lrval;
};
struct Segment_tree{
node x;
int lazy;
}tree[maxn<<2];
void pushup(int rt){
tree[rt].x.lc=tree[rt<<1].x.lc;
tree[rt].x.rc=tree[rt<<1|1].x.rc;
tree[rt].x.val=tree[rt<<1].x.val+tree[rt<<1|1].x.val-(tree[rt<<1].x.rc==tree[rt<<1|1].x.lc);
tree[rt].x.val=min(tree[rt].x.val,min(tree[rt<<1].x.rval+tree[rt<<1|1].x.val,tree[rt<<1].x.val+tree[rt<<1|1].x.lval));
tree[rt].x.lval=tree[rt<<1].x.lval+tree[rt<<1|1].x.val-(tree[rt<<1].x.rc==tree[rt<<1|1].x.lc);
tree[rt].x.lval=min(tree[rt].x.lval,min(tree[rt<<1].x.lrval+tree[rt<<1|1].x.val,tree[rt<<1].x.lval+tree[rt<<1|1].x.lval));
tree[rt].x.rval=tree[rt<<1].x.val+tree[rt<<1|1].x.rval-(tree[rt<<1].x.rc==tree[rt<<1|1].x.lc);
tree[rt].x.rval=min(tree[rt].x.rval,min(tree[rt<<1].x.rval+tree[rt<<1|1].x.rval,tree[rt<<1].x.val+tree[rt<<1|1].x.lrval));
tree[rt].x.lrval=tree[rt<<1].x.lval+tree[rt<<1|1].x.rval-(tree[rt<<1].x.rc==tree[rt<<1|1].x.lc);
tree[rt].x.lrval=min(tree[rt].x.lrval,min(tree[rt<<1].x.lrval+tree[rt<<1|1].x.rval,tree[rt<<1].x.lval+tree[rt<<1|1].x.lrval));
}
void build(int rt,int l,int r){
if(l==r){
tree[rt].x.val=tree[rt].x.lval=tree[rt].x.rval=1;//初始化要注意
tree[rt].x.lc=tree[rt].x.rc=c[l];
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void update(int rt,int x){
tree[rt].lazy+=x;
tree[rt].x.lc+=x;
tree[rt].x.rc+=x;
}
void pushdown(int rt){
if(tree[rt].lazy==0) return;
update(rt<<1,tree[rt].lazy);
update(rt<<1|1,tree[rt].lazy);
tree[rt].lazy=0;
}
void modify(int rt,int l,int r,int s,int t,int p){
if(s<=l&&r<=t){
update(rt,p);
return;
}
int mid=(l+r)>>1;
pushdown(rt);
if(s<=mid) modify(rt<<1,l,mid,s,t,p);
if(t>mid) modify(rt<<1|1,mid+1,r,s,t,p);
pushup(rt);
}
node query(int rt,int l,int r,int s,int t){
if(s<=l&&r<=t) return tree[rt].x;
int mid=(l+r)>>1;
pushdown(rt);
if(t<=mid) return query(rt<<1,l,mid,s,t);
if(s>mid) return query(rt<<1|1,mid+1,r,s,t);
node resl=query(rt<<1,l,mid,s,t);
node resr=query(rt<<1|1,mid+1,r,s,t);
node res={};
res.lc=resl.lc;
res.rc=resr.rc;
res.val=resl.val+resr.val-(resl.rc==resr.lc);
res.val=min(res.val,min(resl.rval+resr.val,resl.val+resr.lval));
res.lval=resl.lval+resr.val-(resl.rc==resr.lc);
res.lval=min(res.lval,min(resl.lval+resr.lval,resl.lrval+resr.val));
res.rval=resl.val+resr.rval-(resl.rc==resr.lc);
res.rval=min(res.rval,min(resl.rval+resr.rval,resl.val+resr.lrval));
res.lrval=resl.lval+resr.rval-(resl.rc==resr.lc);
res.lrval=min(res.lrval,min(resl.lrval+resr.rval,resl.lval+resr.lrval));
return res;
}
void Solve(){
n=read();
int la=0;
for(int i=1,x;i<=n;++i){
x=read();
c[i]=x-la;
la=x;
}
build(1,1,n);
q=read();
char ccc[3];
for(int i=1,s,t,x,y;i<=q;++i){
scanf("%s",ccc);
s=read();
t=read();
if(ccc[0]=='B'){
if(s==t||s==t-1) printf("1\n");
else{
node ans=query(1,1,n,s+1,t);
printf("%lld\n",ans.val);
}
}else{
x=read();
y=read();
modify(1,1,n,s,s,x);
if(s<t) modify(1,1,n,s+1,t,y);
if(t<n) modify(1,1,n,t+1,t+1,-1*(x+y*(t-s)));
}
}
}
signed main(){
Solve();
return 0;
}

浙公网安备 33010602011771号