题面

首先感谢这篇题解,是思路来源


看到等差数列,就会想到差分,又有区间加,很容易想到线段树维护差分。再注意点细节,\(A\)操作完美解决
然后就是爆炸恶心的\(B\)操作,之前看一堆题解的解释都不怎么明白,就自己脑补+看上面那篇题解乱搞出了个相对合理点的解释……
用\(0/1/2/3\)分别表示一个差分区间统计答案时,是否跨越原区间左右端点。\(s[0/1/2/3]\)分别表示每个状态的最少可以划分出来的等差数列个数。
合并方式如下:

/*定义差分b[i]=a[i+1]-a[i]
假设要查询区间[S,T],对应到差分数组实际查询的是区间[S,T-1]
所以一个节点如果在差分数组上维护的区间是[a,b],在原数组上维护的实际上是区间[a,b+1]*/

//s[0]表示原数组中区间为(S,T)的答案
//s[1]表示原数组中区间为(S,T]的答案
//s[2]表示原数组中区间为[S,T)的答案
//s[3]表示原数组中区间为[S,T]的答案

s[0]= min(s[1]+ s[2]- ( vr==Y.vl), min(s[0]+ s[2], s[1]+s[0] ) );

s[1]= min(s[1]+ Y.s[3]- ( vr==Y.vl), min(s[1]+ s[1], s[0]+s[3] ) );

s[2]= min(s[3]+ s[2]- ( vr==Y.vl), min(s[2]+ s[2], s[3]+s[0] ) );

s[3]= min(s[3]+ s[3]- ( vr==Y.vl), min(s[3]+ s[1], s[2]+s[3] ) );

输出时直接输出\(s[3]\)就OK了

\(p.s.\) \(n==1\)时不用建树,否则\(RE\)

代码:

#include <bits/stdc++.h>
#define N 100005
using namespace std;

int a[N],n;

#define bas int l,int r,int o
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1

struct node{
    int s[4];
    long long vl,vr;
    node operator +(const node &Y)const{
        node Z;
        Z.vl=vl,Z.vr=Y.vr;
        Z.s[0]= min(s[1]+ Y.s[2]- ( vr==Y.vl), min(s[0]+ Y.s[2], s[1]+Y.s[0] ) );
        Z.s[1]= min(s[1]+ Y.s[3]- ( vr==Y.vl), min(s[1]+ Y.s[1], s[0]+Y.s[3] ) );
        Z.s[2]= min(s[3]+ Y.s[2]- ( vr==Y.vl), min(s[2]+ Y.s[2], s[3]+Y.s[0] ) );
        Z.s[3]= min(s[3]+ Y.s[3]- ( vr==Y.vl), min(s[3]+ Y.s[1], s[2]+Y.s[3] ) );
        return Z;
    }
};
struct qwq{
    long long tag[N<<2];
    node t[N<<2];
    void pushdown(int o){
        t[o<<1].vl+= tag[o], t[o<<1].vr+= tag[o];
        t[o<<1|1].vl+= tag[o], t[o<<1|1].vr+= tag[o];
        tag[o<<1]+= tag[o], tag[o<<1|1]+= tag[o];
        tag[o]=0;
    }
    void build(bas){
        tag[o]=0;
        if(l==r){
            t[o].vl= t[o].vr= a[l];
            t[o].s[1]= t[o].s[2]= t[o].s[3]= 1, t[o].s[0]=0;//两个数时和一个数时等差数列数量都是1
            return;
        }
        int mid=(l+r)>>1;
        build(lson),build(rson);
        t[o]= t[o<<1]+ t[o<<1|1];
    }
    void update(bas,int L,int R,long long x){
        if(L<=l && r<=R){
            t[o].vl+= x, t[o].vr+= x;
            tag[o]+= x;
            return;
        }
        if(tag[o]) pushdown(o);
        int mid= (l+r)>>1;
        if(L<= mid) update(lson,L,R,x);
        if(R> mid) update(rson,L,R,x);
        t[o]= t[o<<1]+ t[o<<1|1];
    }
    node query(bas,int L,int R){
        if(L<= l && r<= R) return t[o];
        if(tag[o]) pushdown(o);
        int mid= (l+r)>>1;
        if(R<=mid) return query(lson,L,R);
        else{
            if(L>mid) return query(rson,L,R);
            else return query(lson,L,R)+query(rson,L,R);
        }
    }
}T;

int main(){
    int q,s,t,c,d,ans,i;
    char op;
    scanf("%d",&n);
    for(i=1;i<=n;++i) scanf("%d",&a[i]);
    for(i=1;i<n;++i) a[i]=a[i+1]-a[i];
    if(n!=1) T.build(1,n-1,1);
    scanf("%d",&q);
    while(q--){
        scanf("\n%c",&op);
        if(op=='A'){
            scanf("%d%d%d%d",&s,&t,&c,&d);
            if(s!=1) T.update(1,n-1,1,s-1,s-1,c);
            if(t!=n) T.update(1,n-1,1,t,t,1ll*d*s-1ll*d*t-c);
            if(s!=t) T.update(1,n-1,1,s,t-1,d);
        } else{
            scanf("%d%d",&s,&t);
            if(t- s+ 1==1) ans=1;
            else{
                node res=T.query(1,n-1,1,s,t-1);
                ans=min((t-s+2)/2,res.s[3]);
            }
            printf("%d\n",ans);
        }
    }
}

洛谷P4243/bzoj1558 [JSOI2009]等差数列(线段树维护差分+爆炸恶心的合并)的更多相关文章

  1. 洛谷 P4747 [CERC2017]Intrinsic Interval 线段树维护连续区间

    题目描述 题目传送门 分析 考虑对于 \([l,r]\),如何求出包住它的长度最短的好区间 做法就是用一个指针从 \(r\) 向右扫,每次查询以当前指针为右端点的最短的能包住 \([l,r]\) 的好 ...

  2. 洛谷 P3373 【模板】线段树 2

    洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...

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

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

  4. 洛谷P2221 [HAOI2012]高速公路(线段树+概率期望)

    传送门 首先,答案等于$$ans=\sum_{i=l}^r\sum_{j=i}^r\frac{sum(i,j)}{C_{r-l+1}^2}$$ 也就是说所有情况的和除以总的情况数 因为这是一条链,我们 ...

  5. 洛谷3822 [NOI2017] 整数 【线段树】【位运算】

    题目分析: 首先这题的询问和位(bit)有关,不难想到是用线段树维护位运算. 现在我们压32位再来看这道题. 对于一个加法操作,它的添加位置可以得到,剩下的就是做不超过32的位移.这样根据压位的理论. ...

  6. 洛谷P4425 [HNOI/AHOI2018]转盘(线段树)

    题意 题目链接 Sol 首先猜一个结论:对于每次询问,枚举一个起点然后不断等到某个点出现时才走到下一个点一定是最优的. 证明不会,考场上拍了3w组没错应该就是对的吧... 首先把数组倍长一下方便枚举起 ...

  7. 洛谷P4425 转盘 [HNOI/AHOI2018] 线段树+单调栈

    正解:线段树+单调栈 解题报告: 传送门! 1551又是一道灵巧连题意都麻油看懂的题,,,,所以先解释一下题意好了,,,, 给定一个n元环 可以从0时刻开始从任一位置出发 每次可以选择向前走一步或者在 ...

  8. 洛谷 P3924 康娜的线段树 解题报告

    P3924 康娜的线段树 题目描述 小林是个程序媛,不可避免地康娜对这种人类的"魔法"产生了浓厚的兴趣,于是小林开始教她\(OI\). 今天康娜学习了一种叫做线段树的神奇魔法,这种 ...

  9. 【洛谷 P3834】 可持久化线段树1(主席树)

    题目链接 主席树=可持久化权值线段树. 如果你不会可持久化线段树,请右转 如果你不会权值线段树,请自行脑补,就是线段树维护值域里有多少个数出现. 可持久化线段树是支持查询历史版本的. 我们对每个数都进 ...

随机推荐

  1. Redis教程(Linux)

    这里汇总了从简单的安装到较为复杂的配置,由浅入深的学习redis... 一 , 安装 1) redis扩展安装 从官网上下载扩展压缩包 wget http://pecl.php.net/get/red ...

  2. PHP中对象是按值传递还是按引用传递?

    1.首先,什么是按值传递和按引用传递? 按值传递就是仅仅把值传递过去,相当于传递的是值的拷贝,而按引用传递传递的是内存的地址. 在 PHP5 中,如果按引用传递,就是将 zval 的地址赋给另一个变量 ...

  3. [转帖]迎战AMD 7nm 64核EPYC 英特尔至强也玩起了胶水以及性价比

    迎战AMD 7nm 64核EPYC 英特尔至强也玩起了胶水以及性价比 Intel 最强CPU 从最开始的双核 到现在的 28核 发展迅猛. https://www.cnbeta.com/article ...

  4. [转帖]TCP和UDP的135、137、138、139、445端口的作用

    TCP和UDP的135.137.138.139.445端口的作用 https://www.cnblogs.com/IvanChen/p/4500698.html 竟然不知道 端口具体是干什么的.. 如 ...

  5. 【学亮IT手记】angularJS+select2多选下拉框实例

     永远保持对大部分知识的好奇心,学习从不枯燥,也没有被逼学习一说,乐此不疲才是该有的心态和境界!!! 引入相关js库: html部分代码: angularJS定义数据源变量:

  6. mysql数据库在linux上的不同登录方式和权限

    在我的上两篇博文里,一篇是安装,一篇是配置远程登录, 提君博客原创 >>提君博客原创  http://www.cnblogs.com/tijun/  << 所以我的mysql的 ...

  7. 关于idea easyui 引入css js

    1.引用官方网站 <link rel="stylesheet" type="text/css" href="http://www.w3cscho ...

  8. Json dump

    json 模块提供了一种很简单的方式来编码和解码JSON数据. 其中两个主要的函数是 json.dumps() 和 json.loads() , 要比其他序列化函数库如pickle的接口少得多. 下面 ...

  9. spring boot+mybatis+generator生成domain大小写问题

    之前遇到一个问题,用generator生成数据库对应的domain,以前都是好好的,那天突然生成的domain都是小写的,因为我数据库里是大写的,后来找到解决办法, <table tableNa ...

  10. kprobe原理解析

    参考  http://www.cnblogs.com/honpey/p/4575928.html kprobe是linux内核的一个重要特性,是一个轻量级的内核调试工具,同时它又是其他一些更高级的内核 ...