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;
}
luogu P4243 [JSOI2009]等差数列 题解的更多相关文章
- 洛谷P4243/bzoj1558 [JSOI2009]等差数列(线段树维护差分+爆炸恶心的合并)
题面 首先感谢这篇题解,是思路来源 看到等差数列,就会想到差分,又有区间加,很容易想到线段树维护差分.再注意点细节,\(A\)操作完美解决 然后就是爆炸恶心的\(B\)操作,之前看一堆题解的解释都不怎 ...
- 【题解】Luogu P4054 [JSOI2009]计数问题
原题传送门 我自闭了qaq 这道题非常简单,因为1<=c<=100,所以直接对每个c开二维树状数组,操作就跟模板一样 写码5分钟,调码半小时,这道题的输入顺序是x1,x2,y1,y2,我真 ...
- [bzoj1558][JSOI2009]等差数列
题目:给定n个数,m个操作,每次给一段区间加一个等差数列或者询问一段区间至少要用多少个等差数列来表示.$n,m\leqslant 10^{5}$ 题解:老套路,维护差分数组,修改操作变成了两个单点加和 ...
- BZOJ.1558.[JSOI2009]等差数列(线段树 差分)
BZOJ 洛谷 首先可以把原序列\(A_i\)转化成差分序列\(B_i\)去做. 这样对于区间加一个等差数列\((l,r,a_0,d)\),就可以转化为\(B_{l-1}\)+=\(a_0\),\(B ...
- [JSOI2009]等差数列
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1558 题解: 考虑这么用线段树进行维护,由于他有区间修改等差数列 很容易想到可以用差分数组来维 ...
- BZOJ1558 [JSOI2009]等差数列 【线段树】
题目链接 BZOJ1558 题解 等差数列,当然是差分一下 差分值相同的连续位置形成等差数列,我们所选的两个等差数列之间可以有一个位置舍弃 例如: \(1 \; 2 \; 3 \; 6 \; 8 \; ...
- 【luogu P5022 旅行】 题解
题目连接:https://www.luogu.org/problemnew/show/P5022 \(NOIP2018 DAY2T1\) 考场上只写了60分,很容易想到当 m = n - 1 时的树的 ...
- JSOI2009 等差数列 和 算术天才⑨与等差数列 和 CH4302 Interval GCD
等差数列 为了检验学生的掌握情况,jyy布置了一道习题:给定一个长度为N(1≤N≤100,000)的数列,初始时第i个数为vi(vi是整数,−100,000≤vi≤100,000),学生们要按照jyy ...
- bzoj 1558: [JSOI2009]等差数列
Description Solution 把原数组变为差分数组,然后剩下的就十分显然了 区间查询用线段树维护 修改操作就是区间加法和两个单点修改 一个等差数列实际上就是 开头一个数字+数值相等的一段 ...
随机推荐
- Docker Compose 实践及梳理
Docker Compose 可以实现 Docker 容器集群的编排,可以通过 docker-compose.yml 文件,定义我们的服务及其需要的依赖,轻松地运行在测试.生产等环境 文档 Produ ...
- TypeScript 中命名空间与模块的理解?区别?
一.模块 TypeScript 与ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块 相反地,如果一个文件不带有顶级的import或者expo ...
- ElasticSearch集成SpringData史上最全查询教程
1.简单介绍 springboot 使用springdata操作es,ElasticsearchRepository使用QueryBuilder构造查询条件 2.集成es //maven集成 < ...
- 将dict.define转化成dict.txt
在使用捷通智能灵云外呼系统V6.1时.需要大量使用到模式码,也就是正则表达式.而老版本365还是使用场景文件. 当要将老版本改编成新版本的时候,需要需要将dict.define文件中的一行行的词条用& ...
- C# Redis学习系列二:Redis基本设置
上一篇:C# Redis学习系列一:Redis的认识.下载.安装.使用 一.redis 设置密码 使用下载好的 redis-cli.exe 指令: 1.设置密码: config set require ...
- 给你一个app,怎么测试
安装卸载 安装卸载路径是否能自己选择,在不同操作系统下(Android.ios)安装是否正常,能正常运行,安装的文件及文件夹是否写入了指定的目录里,安装来自不同来源的(应用宝.360助手)下是否正常. ...
- P4770-[NOI2018]你的名字【SAM,线段树合并】
正题 题目链接:https://www.luogu.com.cn/problem/P4770 题目大意 给出一个长度为\(n\)的字符串\(S\).\(q\)次询问给出一个串\(T\)和一个区间\([ ...
- Python读取ini配置文件(接口自动测试必备)
前言 大家应该接触过.ini格式的配置文件.配置文件就是把一些配置相关信息提取出去来进行单独管理,如果以后有变动只需改配置文件,无需修改代码. 特别是后续做自动化的测试,代码和数据分享,进行管理.比如 ...
- 升级sudo版本
1.查看sudo版本 sudo -V 2.下载sudo最新安装文件 sudo官方地址: https://www.sudo.ws/ 下载地址:https://www.sudo.ws/dist/ 3.解压 ...
- AOJ/高等排序习题集
ALDS1_5_B-MergeSort. Description: Write a program of a Merge Sort algorithm implemented by the follo ...