题目描述

传送门

题目大意:给定一个长度为N的数列,初始时第i个数为vi。
操作(1)A s t a b在序列的[s,t]区间上加上初值为a,步长为b的等差数列。即vi变为vi+a+b*(i-s)
操作(2)B s t询问当前序列的[s,t]区间最少能划分成几段,使得每一段都是等差数列。

题解

首先可以想到的是线段树维护的是差分后的值,vali=vi+1−vival_i=v_{i+1}-v_i,而不是原序列的值。
那么对于修改操作来说可以分成两部分
(1)单点修改,valx−1+=a,valy−=((y−x)∗b+a)val_{x-1}+=a,val_y-=((y-x)*b+a)
(2)区间修改 val[x,y−1]+=bval_{[x,y-1]}+=b

比较麻烦的是操作二,刚开始看的时候以为就是直接维护区间颜色段数。对于两个等差数列的首尾差是单独的颜色可以忽略不计。所以就需要各种分情况讨论。
大体上的思路是维护区间左右两端单独数的个数(没有连续的相同数值) ,以及除去两端单独数中间部分的答案。
随便写个数列,划分一下会发现,如果某端的单独数个数为pp,那么最少可以划分成(p+1)/2(p+1)/2
中间的部分在合并答案的时候需要各种分类讨论,我把所有需要特判的特殊情况注释到了程序中
注释中的第一行是差分后的答案
注释中的第二行是符合差分的合法序列,和最小的划分方案。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100003
using namespace std;
struct data{int sum,ls,rs,tag,ll,rr,all;
}tr[N*4];
int n,m,a[N],val[N],pos[N];
data update(data l,data r)
{data now; now.tag=0;now.ls=l.ls; now.rs=r.rs;//ls,rs表示区间左右端点的数值 now.ll=l.ll; now.rr=r.rr;//ll,rr表示区间左右两端单独数的个数(没有连续的相同数值) if (l.all) //all表示区间中是否都是单独数 if (l.rs==r.ls) now.ll--;else now.ll+=r.ll;if (r.all)if (l.rs==r.ls) now.rr--;else now.rr+=l.rr;now.sum=l.sum+r.sum;if (l.all&&r.all&&l.rs!=r.ls) now.all=1;else now.all=0;if (l.all) {if (l.rs==r.ls) {if (r.all) now.sum=1;// 1 2 3 | 3 2 1else if (r.ll) now.sum+=(r.ll-1)/2+1; // 1 2 3 5 4 | 4 2 3 3 2 // (1 2) (4 7) |(12 16 20) (22 25 28)| (30)}}  else if (l.rr) {if (l.rs==r.ls){if (r.all) now.sum+=(l.rr-1)/2+1;// 1 2 2 3|3 2 1 3// (1) |(2 4 6) (9 12)| (14 15) (18)else if (r.ll) now.sum+=(r.ll-1)/2+(l.rr-1)/2+1; // 1 2 2 3 | 3 2 2 1// (1) |(2 4 6) (9) (12 14 16)| (17)else now.sum+=(l.rr-1)/2; //1 2 2 3 |3 3 3 1// (1) (2 4 6) (9 12 15 18) (19)}else if (!r.all) now.sum+=(l.rr+r.ll)/2; // 1 2 2 3 | 4 5 5 7 //1 |(2 4 6) (9 13) (18 23)| 30}else {if (l.rs==r.ls) {if (!r.all) {if (r.ll) now.sum+=(r.ll-1)/2; // 1 2 2 | 2 3 3// (1) (2 4 6 8) (11 14)else now.sum--; //1 2 2| 2 2 1// (1) (2 4 6 8 10) (11)}}else {if (!r.all&&r.ll) now.sum+=r.ll/2; //1 2 2| 3 2 2// (1) (2 4 6) (9 11 13)}}return now;
}
void build(int now,int l,int r)
{if (l==r) {tr[now].sum=0; tr[now].ll=tr[now].rr=tr[now].all=1;tr[now].ls=tr[now].rs=a[l];pos[l]=now;return;}int mid=(l+r)/2;build(now<<1,l,mid);build(now<<1|1,mid+1,r);tr[now]=update(tr[now<<1],tr[now<<1|1]);
}
void change(int now,int val)
{tr[now].ls+=val; tr[now].rs+=val;tr[now].tag+=val;
}
void pushdown(int now)
{if (tr[now].tag){change(now<<1,tr[now].tag);change(now<<1|1,tr[now].tag);tr[now].tag=0;}
}
data qjsum(int now,int l,int r,int ll,int rr)
{if (ll<=l&&r<=rr) return tr[now];int mid=(l+r)/2;pushdown(now); data ans; bool pd=false;if (ll<=mid) ans=qjsum(now<<1,l,mid,ll,rr),pd=true;if (rr>mid) {if (!pd) ans=qjsum(now<<1|1,mid+1,r,ll,rr);else ans=update(ans,qjsum(now<<1|1,mid+1,r,ll,rr));}return ans;
}
void pointchange(int now,int l,int r,int x,int val)
{if (l==r) {tr[now].ls=tr[now].rs+=val;tr[now].sum=0; tr[now].ll=tr[now].rr=tr[now].all=1;return;}int mid=(l+r)/2;pushdown(now);if (x<=mid) pointchange(now<<1,l,mid,x,val);else pointchange(now<<1|1,mid+1,r,x,val);tr[now]=update(tr[now<<1],tr[now<<1|1]);
}
void qjadd(int now,int l,int r,int ll,int rr,int val)
{if (ll>rr) return;if (ll<=l&&r<=rr) {change(now,val);return;}int mid=(l+r)/2;pushdown(now);if (ll<=mid) qjadd(now<<1,l,mid,ll,rr,val);if (rr>mid) qjadd(now<<1|1,mid+1,r,ll,rr,val);tr[now]=update(tr[now<<1],tr[now<<1|1]);
}
int main()
{freopen("a.in","r",stdin);freopen("my.out","w",stdout);scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&val[i]);for (int i=1;i<=n-1;i++) a[i]=val[i+1]-val[i];n--; if (n) build(1,1,n);scanf("%d",&m);for (int i=1;i<=m;i++) {char s[10]; int x,y; scanf("%s%d%d",s+1,&x,&y);if (s[1]=='A') {int a,b; scanf("%d%d",&a,&b);if (x-1>=1&&x-1<=n) pointchange(1,1,n,x-1,a); if (y<=n) pointchange(1,1,n,y,-((y-x)*b+a));qjadd(1,1,n,x,y-1,b);}if (s[1]=='B') {data t; if (x<=y-1) t=qjsum(1,1,n,x,y-1);else t.sum=1;if (x==y) printf("%d\n",1);else {if (t.sum==0) printf("%d\n",(y-x+2)/2);else printf("%d\n",t.sum+(t.ll+1)/2+(t.rr+1)/2);}    }}
}

bzoj 1558: [JSOI2009]等差数列 (线段树)相关推荐

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

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

  2. BZOJ 2124 等差子序列 线段树维护哈希

    $ \Rightarrow $ 戳我进BZOJ原题 等差子序列 Time Limit: 3 Sec $ \quad $ Memory Limit: 259 MB Description 给一个 $ 1 ...

  3. BZOJ.3938.Robot(李超线段树)

    BZOJ UOJ 以时间\(t\)为横坐标,位置\(p\)为纵坐标建坐标系,那每个机器人就是一条\(0\sim INF\)的折线. 用李超线段树维护最大最小值.对于折线分成若干条线段依次插入即可. 最 ...

  4. BZOJ 4422 Cow Confinement (线段树、DP、扫描线、差分)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4422 我真服了..这题我能调一天半,最后还是对拍拍出来的...脑子还是有病啊 题解: ...

  5. BZOJ 1135 [POI2009]Lyz 线段树

    题意:链接 方法:线段树维护子区间最值. 解析: 我们可以推出来一个式子. 就是如果满足题意的话. 那么任意一个子区间[l,r] f[i]表示穿i的鞋的人数 (r−l+1+d)∗k>=∑f[i] ...

  6. BZOJ[1135][POI2009]Lyz 线段树

    传送门ber~ 如果某时不合法,那一定存在某段满足 (r−l+1+d)∗k<Σl≤i≤rnumi(r−l+1+d)∗k<Σl≤i≤rnumi (r-l+1+d)*k (其中 numinum ...

  7. bzoj 1503 (权值线段树)

    由于蒟蒻实在是ttttttai 菜了,于是开始了学习主席树,权值线段树作为主席树的前置知识,于是蒟蒻各种百度百度,谷歌谷歌,抄网上的代码,然后终于A了这个题目.也还算是有一点收获. 题目:芝麻开门 题 ...

  8. [FJOI 2016]bzoj 4408 神秘数 - 线段树

    题目大意:给你一列数,多次询问用一个区间的数字形成一个可重集合,最小的不能被表示为其一个子集的数字是多少. 题解:考虑给你一个可重集合你怎么算:从小到大排序,假设用前x个数字不能表示的最小都数字是an ...

  9. BZOJ.4821.[SDOI2017]相关分析(线段树)

    BZOJ LOJ 洛谷 恶心的拆式子..然后就是要维护\(\sum x_i,\ \sum y_i,\ \sum x_iy_i,\ \sum x_i^2\). 操作三可以看成初始化一遍,然后同操作二. ...

最新文章

  1. django 2.0路由配置变化
  2. 关于生sql中的空值
  3. 【机器学习】集成学习之boosting AdaBoost
  4. shutil.rmtree()
  5. php v9 邮箱登陆,PHPCMS v9会员登录支持Email登录的实现方法
  6. java编程技巧_Java编程技巧
  7. oracle 日期格式化 修改_java学习笔记:时间日期类
  8. python中breakpoint什么意思_it/breakpoint是什么意思
  9. 阿里云申请免费ssl证书并配置nginx
  10. 数据字典模块设计_使用正则表达式采集整站小说数据小说精品屋爬虫模块的设计与实现...
  11. 肿瘤基因组变异相关概念
  12. 联想商务机M8000T风扇狂转解决方法
  13. 《GPU编程与CG语言之阳春白雪下里巴人》 读书笔记2
  14. 福特汉姆计算机专业,福特汉姆大学计算机
  15. dom4j解析xml格式字符串获取标签属性和内容
  16. 工业物联网·能耗监控智慧空调接入华为云解决方案
  17. 程序员分级-八个等级
  18. bootstrap常用样式整理
  19. 作为产品经理的你,画原型图时崩溃过吗?
  20. Es refresh index

热门文章

  1. JAVA封装|继承|多态
  2. 汽修汽配管理系统怎样的实用
  3. 服务器护卫神怎么上传文件,护卫神异地备份系统怎么将数、据上传到服务器上?...
  4. Houdini学习笔记(一) 利用vex制作简单的闪电效果
  5. excel怎么能把含阿拉伯数字筛选出来
  6. 【MyAndroid】viewpage+cardView卡片叠层效果展示(2)--100个经典UI设计模板(98/100)
  7. 【工具篇】Unity自定义取色板颜色获取
  8. 线性无关向量不一定正交
  9. Beyond Compare对比文件不同
  10. 安装配置服务器失败的解决