题目链接

BZOJ1558

题解

等差数列,当然是差分一下

差分值相同的连续位置形成等差数列,我们所选的两个等差数列之间可以有一个位置舍弃

例如:

\(1 \; 2 \; 3 \; 6 \; 8 \; 10\)

差分后是

\(1\; 1\; 3 \; 2\; 2\)

左边两个\(1\)形成等差,右边两个\(2\)形成等差,中间的\(3\)位于两个等差数列的边界,可以舍弃

所以现在问题就转化为了:

在一个区间中选定若干个相同数字的区间,区间之间可以有一个空隙,求最少的区间数

可以用线段树维护

每个节点储存一下左右端点的值,以及\(c[2][2]\)表示左右端点选与不选时的答案

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define cls(s) memset(s,0,sizeof(s))
#define LL long long int
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,Q,A[maxn],D[maxn];
LL cnt[maxn << 2][2][2],add[maxn << 2],rn[maxn << 2],ln[maxn << 2];
void pd(int u){
if (add[u]){
ln[ls] += add[u]; rn[ls] += add[u]; add[ls] += add[u];
ln[rs] += add[u]; rn[rs] += add[u]; add[rs] += add[u];
add[u] = 0;
}
}
void pup(int u){
ln[u] = ln[ls]; rn[u] = rn[rs];
if (rn[ls] == ln[rs]){
cnt[u][0][0] = cnt[ls][0][1] + cnt[rs][1][0] - 1;
cnt[u][0][1] = cnt[ls][0][1] + cnt[rs][1][1] - 1;
cnt[u][1][0] = cnt[ls][1][1] + cnt[rs][1][0] - 1;
cnt[u][1][1] = cnt[ls][1][1] + cnt[rs][1][1] - 1;
}
else {
cnt[u][0][0] = min(cnt[ls][0][0] + cnt[rs][1][0],cnt[ls][0][1] + cnt[rs][0][0]);
cnt[u][0][1] = min(cnt[ls][0][1] + cnt[rs][0][1],cnt[ls][0][0] + cnt[rs][1][1]);
cnt[u][1][0] = min(cnt[ls][1][1] + cnt[rs][0][0],cnt[ls][1][0] + cnt[rs][1][0]);
cnt[u][1][1] = min(cnt[ls][1][1] + cnt[rs][0][1],cnt[ls][1][0] + cnt[rs][1][1]);
}
}
void build(int u,int l,int r){
if (l == r){
cnt[u][1][1] = 1; cnt[u][0][1] = cnt[u][1][0] = 1; cnt[u][0][0] = 0;
ln[u] = rn[u] = D[l];
return;
}
int mid = l + r >> 1;
build(ls,l,mid);
build(rs,mid + 1,r);
pup(u);
}
void modify(int u,int l,int r,int L,int R,int v){
if (l >= L && r <= R){
ln[u] += v; rn[u] += v; add[u] += v;
return;
}
pd(u);
int mid = l + r >> 1;
if (mid >= L) modify(ls,l,mid,L,R,v);
if (mid < R) modify(rs,mid + 1,r,L,R,v);
pup(u);
}
struct node{
LL ln,rn,cnt[2][2];
node(){}
node(LL a,LL b,LL c[][2]):ln(a),rn(b) {
cnt[0][0] = c[0][0]; cnt[0][1] = c[0][1];
cnt[1][0] = c[1][0]; cnt[1][1] = c[1][1];
}
};
node query(int u,int l,int r,int L,int R){
if (l >= L && r <= R) return node(ln[u],rn[u],cnt[u]);
pd(u);
int mid = l + r >> 1;
if (mid >= R) return query(ls,l,mid,L,R);
if (mid < L) return query(rs,mid + 1,r,L,R);
node a = query(ls,l,mid,L,R),b = query(rs,mid + 1,r,L,R);
LL c[2][2];
if (a.rn == b.ln){
c[0][0] = a.cnt[0][1] + b.cnt[1][0] - 1;
c[0][1] = a.cnt[0][1] + b.cnt[1][1] - 1;
c[1][0] = a.cnt[1][1] + b.cnt[1][0] - 1;
c[1][1] = a.cnt[1][1] + b.cnt[1][1] - 1;
}
else {
c[0][0] = min(a.cnt[0][0] + b.cnt[1][0],a.cnt[0][1] + b.cnt[0][0]);
c[0][1] = min(a.cnt[0][1] + b.cnt[0][1],a.cnt[0][0] + b.cnt[1][1]);
c[1][0] = min(a.cnt[1][1] + b.cnt[0][0],a.cnt[1][0] + b.cnt[1][0]);
c[1][1] = min(a.cnt[1][1] + b.cnt[0][1],a.cnt[1][0] + b.cnt[1][1]);
}
return node(a.ln,b.rn,c);
}
int main(){
n = read();
REP(i,n) A[i] = read(),D[i] = A[i] - A[i - 1];
build(1,1,n);
Q = read();
char opt; LL l,r,a,b;
while (Q--){
opt = getchar(); while (opt != 'A' && opt != 'B') opt = getchar();
l = read(); r = read();
if (opt == 'A'){
a = read(); b = read();
modify(1,1,n,l,l,a);
if (l < r) modify(1,1,n,l + 1,r,b);
if (r < n) modify(1,1,n,r + 1,r + 1,-(a + (r - l) * b));
}
else {
if (l == r) puts("1");
else{
node u = query(1,1,n,l + 1,r);
printf("%lld\n",u.cnt[1][1]);
}
}
}
return 0;
}

BZOJ1558 [JSOI2009]等差数列 【线段树】的更多相关文章

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

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

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

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

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

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

  4. [BZOJ4373]算术天才⑨与等差数列(线段树)

    [l,r]中所有数排序后能构成公差为k的等差数列,当且仅当: 1.区间中最大数-最小数=k*(r-l) 2.k能整除区间中任意两个相邻数之差,即k | gcd(a[l+1]-a[l],a[l+2]-a ...

  5. 【BZOJ4373】算术天才⑨与等差数列 [线段树]

    算术天才⑨与等差数列 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 算术天才⑨非常喜欢和等 ...

  6. BZOJ 4373 算术天才⑨与等差数列 线段树+set(恶心死我了)

    mdzz,这道题重构了4遍,花了一个晚上... 满足等差数列的条件: 1. 假设min是区间最小值,max是区间最大值,那么 max-min+k(r−l) 2. 区间相邻两个数之差的绝对值的gcd=k ...

  7. 【BZOJ4373】算术天才⑨与等差数列 线段树+set

    [BZOJ4373]算术天才⑨与等差数列 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次他会给出询问l,r,k, ...

  8. BZOJ 4373算术天才⑨与等差数列(线段树)

    题意:给你一个长度为n的序列,有m个操作,写一个程序支持以下两个操作: 1. 修改一个值 2. 给出三个数l,r,k, 询问:如果把区间[l,r]的数从小到大排序,能否形成公差为k的等差数列. n,m ...

  9. bzoj 4373 算术天才⑨与等差数列——线段树+set

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4373 能形成公差为k的等差数列的条件:mx-mn=k*(r-l) && 差分 ...

随机推荐

  1. Apache Maven(六):存储库

    Maven 存储库主要是存放一些第三方依赖jar包等. 严格来说,只有两种存储库:本地和远程,本地存储库是指您远程下载到本地的一个缓存,还包含尚未发布的临时构建文件.远程存储库是指一些可以通过各种协议 ...

  2. Asp.Net Core 使用Docker进行容器化部署(二)使用Nginx进行反向代理

    上一篇介绍了Asp.Net 程序在Docker中的部署,这篇介绍使用Nginx对Docker的实例进行反向代理 一.修改Nginx配置文件 使用winscp链接Liunx服务器,在/ect/nginx ...

  3. laydate js动态添加时间

    $("#test2").click(function(){ var input=$('<input/>'); $("#test1").append( ...

  4. Java学习笔记三:Java的变量、常量、变量的类型及使用规则

    Java的变量.常量.变量的类型及使用规则 每一种语言都有一些具有特殊用途的词,Java也不例外,它们被称为关键字.关键字对 Java 的编译器有着特殊的意义. 一:Java中的关键字: 注:Java ...

  5. 清华大学《C++语言程序设计基础》线上课程笔记01---基础概念与一些注意事项

    使用除法的注意事项 double b = 4.0 * 1/239.0; 因为整数相除结果取整,如果参数写1/239,结果就都是0 浮点数注意事项 浮点数是近似存储,所以不能直接比较两个浮点数的大小, ...

  6. Unicode控制字符

    Unicode控制字符就是特殊的Unicode字符 控制字符转义代码对照表 Unicode-控制字符 ‎LRM ‏RLM ‍ZWJ ‌ZWNJ ‪LRE ‭LRO ‮RLO ‬PDF NADS  ...

  7. 按平均成绩从高到低显示所有学生的“数据库”、“企业管理”、“英语”三门的课程成绩,按如下形式显示: 学生ID,,数据库,企业管理,英语,有效课程数,有效平均分

    SELECT S# as 学生ID ,(SELECT score FROM SC WHERE SC.S#=t.S# AND C#='004') AS 数据库 ,(SELECT score FROM S ...

  8. PHP.45-TP框架商城应用实例-后台20-权限管理-RBAC表构造与代码生成

    权限管理 三张主表{p39_privilege(权限).p39_role(角色).p39_admin(管理)} 两张中间表{p39_role_pri(角色-权限).p39_admin_role(管理- ...

  9. docker学习(一) 安装

    一.什么是docker 参见https://baike.baidu.com/item/Docker/13344470?fr=aladdin 个人的理解是,通俗来说,就是相当于一个方便携带且个体独立的虚 ...

  10. 第5模块闯关Bootstrap

    “行(row)”必须包含在 .container (固定宽度)或 .container-fluid (100% 宽度)中,以便为其赋予合适的排列(aligment)和内补(padding). 通过“行 ...