前言:

这题真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;
}

luogu P4243 [JSOI2009]等差数列 题解的更多相关文章

  1. 洛谷P4243/bzoj1558 [JSOI2009]等差数列(线段树维护差分+爆炸恶心的合并)

    题面 首先感谢这篇题解,是思路来源 看到等差数列,就会想到差分,又有区间加,很容易想到线段树维护差分.再注意点细节,\(A\)操作完美解决 然后就是爆炸恶心的\(B\)操作,之前看一堆题解的解释都不怎 ...

  2. 【题解】Luogu P4054 [JSOI2009]计数问题

    原题传送门 我自闭了qaq 这道题非常简单,因为1<=c<=100,所以直接对每个c开二维树状数组,操作就跟模板一样 写码5分钟,调码半小时,这道题的输入顺序是x1,x2,y1,y2,我真 ...

  3. [bzoj1558][JSOI2009]等差数列

    题目:给定n个数,m个操作,每次给一段区间加一个等差数列或者询问一段区间至少要用多少个等差数列来表示.$n,m\leqslant 10^{5}$ 题解:老套路,维护差分数组,修改操作变成了两个单点加和 ...

  4. BZOJ.1558.[JSOI2009]等差数列(线段树 差分)

    BZOJ 洛谷 首先可以把原序列\(A_i\)转化成差分序列\(B_i\)去做. 这样对于区间加一个等差数列\((l,r,a_0,d)\),就可以转化为\(B_{l-1}\)+=\(a_0\),\(B ...

  5. [JSOI2009]等差数列

    链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1558 题解: 考虑这么用线段树进行维护,由于他有区间修改等差数列 很容易想到可以用差分数组来维 ...

  6. BZOJ1558 [JSOI2009]等差数列 【线段树】

    题目链接 BZOJ1558 题解 等差数列,当然是差分一下 差分值相同的连续位置形成等差数列,我们所选的两个等差数列之间可以有一个位置舍弃 例如: \(1 \; 2 \; 3 \; 6 \; 8 \; ...

  7. 【luogu P5022 旅行】 题解

    题目连接:https://www.luogu.org/problemnew/show/P5022 \(NOIP2018 DAY2T1\) 考场上只写了60分,很容易想到当 m = n - 1 时的树的 ...

  8. JSOI2009 等差数列 和 算术天才⑨与等差数列 和 CH4302 Interval GCD

    等差数列 为了检验学生的掌握情况,jyy布置了一道习题:给定一个长度为N(1≤N≤100,000)的数列,初始时第i个数为vi(vi是整数,−100,000≤vi≤100,000),学生们要按照jyy ...

  9. bzoj 1558: [JSOI2009]等差数列

    Description Solution 把原数组变为差分数组,然后剩下的就十分显然了 区间查询用线段树维护 修改操作就是区间加法和两个单点修改 一个等差数列实际上就是 开头一个数字+数值相等的一段 ...

随机推荐

  1. windows操作系统和java常识

    一.java5和java8版本更新很大,现在都是java8; 二.数据存储最小单位Byte字节八个比特位: 三.没有图形操作界面的windows系统: 四.java语言跨平台性:JVM充当不同操作系统 ...

  2. oh,我的老伙计,你看看这近五十个dapr视频

    oh,我的老伙计,你看看这近五十个 dapr 视频.这不就是你想要的视频资料吗?快来捡走吧! 开始了,但是没完全开始 Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的. ...

  3. [Linux系列]DNS系列理论笔记与DNS服务器配置

    0x01 基础术语 DNS(Domain Name System,域名系统),域名和IP地址相互映射的一个分布式数据库,简而言之就是通过更易记忆的域名代替IP去访问一个网站. FQDN(Fully Q ...

  4. java版gRPC实战之五:双向流

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. 谈谈如何进阶Java高级工程师

    从入门到瓶颈(++文末附学习脑图++) 首先,先自我介绍一下,楼主94年的,四川人,普通大专毕业. 第一阶段 实习阶段 2015年,实习阶段去浙江温州(没错,就是皮革厂的那个地方)找了份软件实施的工作 ...

  6. Android实现自动登录和记住密码

    效果图: 在勾选自动登录后下次打开软件会直接跳过登录界面 代码: protected void onCreate(Bundle savedInstanceState) { super.onCreate ...

  7. Cookie和Session的介绍与认识

    Cookie: cookie是一种客户端的状态管理技术. 当浏览器向服务器发送请求的时候,服务器会将少量的数据以set-cookie消息头的方式发送给浏览器,当浏览器再次访问服务器时,会将这些数据以c ...

  8. Python爬无止境,获得王者荣耀全部高清皮肤

    作为一名热爱王者两年的程序员,早就想爬取所有英雄皮肤的高清照片,在设个幻灯片放映,真香,这次只用16行代码就能实现,对于新手拿这个作为实战练手项目既简单又容易上手,快来尝试下. 百度"王者荣 ...

  9. xml字符串转成数组(php)

    1 $str = '<xml> 2 <ToUserName> <![CDATA[gh_fc0a06a20993]]> </ToUserName> 3 & ...

  10. 网站URL Rewrite(伪静态)设置方法

    1.如果您的服务器支持.htaccess,则无需设置,网站根目录下的.htaccess已经设置好规则.规则详情:http://download.destoon.com/rewrite/htaccess ...