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;
}
posted @ 2020-11-23 19:11  “起个名字真难♘”  阅读(110)  评论(4)    收藏  举报