题目类型:差分,线段树

传送门:>Here<

题意:给出一个数列,每次给一个区间对应的加上一个等差数列,并询问某一个元素目前的值。

解题思路

所谓差分,我个人的理解就是用\(O(1)\)的方法来维护前缀和,当然查询变为了\(O(n)\)。差分就好像将前缀和变成了一个数一样——当一段区间需要全部加上\(k\)时:差分数组某一位上\(+k\),意味着这之后的所有元素都将\(+k\)。就好像一条带子拖到最后了。因此我们如果仅仅操作一个区间的话,那么要把后面多出来的带子减掉,于是我们再另外加一条负的带子在后面。

刚才谈论整个区间都加一个相同的数。如果整个区间加的是一个等差数列呢?相当于这个区间内所加的数,每个都比前面的多加\(d\)。效果就等价于在差分数组中,令这个区间的每个元素加上\(d\)。然后末尾要减去末项。依然使用刚才的比喻,将那么多条相同的带子依次叠放,假设区间长度是\(l\),那么最后一个元素那里肯定放着\(l\)条带子了。而我们在最后需要把这\(l\)条带子全部减掉。

因此,如果用差分来维护这道题,我们来总结一下步骤:(按照题意,等差数列的更新方法是\(l \ r \ k \ d\),代表左端点,右端点,首项,公差;设差分数组为\(s\))

  • 令\(s[l]+=k\)

  • 令\(s[l+1..r]+=d\)

  • 令\(s[r+1]-=k+d*(r-l)\)(末项)

由此我们发现,对于大多数的情况都是\(+d\),因此转化为一个区间更新的问题。差分数组的统计方法我们已经很熟悉了,需要从头遍历。因此元素\(p\)现在的值应该是:初始值 + \(s[1..p]\),因此转化为一个区间查询的问题

因此我们可以用线段树方便地\(O(logn)\)维护好

反思

一直以为差分和线段树维护的几乎是同一个东西,却从来没想过线段树可以用来维护差分!线段树维护差分,就好像求和的和。然而等差数列就好像是三维的一样,先由差分转化为二维,然后由线段树转化为线性。

正好像我们在找规律时所作的一样,差,差之差,差之差之差。那么这道题就好像倒过来,和,和的和,和的和的和……

Code

不需要建树,线段树写起来好像异常短小精悍……\(qwq\)


/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = 0; int w = 1; register char c = getchar();
for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
if(c == '-') w = -1, c = getchar();
for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int N,M,opt,l,r,x,y;
int a[MAXN];
int val[MAXN<<2],lazy[MAXN<<2];
struct SegmentTree{
inline void pushdown(int rt, int l, int r){
if(lazy[rt]){
int mid = (l+r)/2;
val[rt<<1] += lazy[rt] * (mid-l+1);
val[rt<<1|1] += lazy[rt] * (r-(mid+1)+1);
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
}
int query(int rt, int l, int r, int x, int y){
if(l > y || r < x) return 0;
if(x <= l && r <= y) return val[rt];
pushdown(rt, l, r);
int mid = (l+r)/2;
return query(rt<<1,l,mid,x,y) + query(rt<<1|1,mid+1,r,x,y);
}
void update(int rt, int l, int r, int x, int y, int k){
if(l > y || r < x) return;
if(x <= l && r <= y){
lazy[rt] += k;
val[rt] += (r-l+1) * k;
return;
}
pushdown(rt,l,r);
int mid = (l+r)/2;
update(rt<<1,l,mid,x,y,k), update(rt<<1|1,mid+1,r,x,y,k);
val[rt] = val[rt<<1] + val[rt<<1|1];
}
}qxz;
int main(){
N = read(), M = read();
for(int i = 1; i <= N; ++i){
a[i] = read();
}
while(M--){
opt = read();
if(opt == 1){
l = read(), r = read(), x = read(), y = read();
qxz.update(1,1,N,l,l,x);
qxz.update(1,1,N,l+1,r,y);
qxz.update(1,1,N,r+1,r+1,-(x+y*(r-l)));
}
else{
x = read();
printf("%d\n", qxz.query(1,1,N,1,x)+a[x]);
}
}
return 0;
}

[洛谷P1438] 无聊的数列的更多相关文章

  1. 洛谷P1438 无聊的数列 [zkw线段树]

    题目传送门 无聊的数列 题目背景 无聊的YYB总喜欢搞出一些正常人无法搞出的东西.有一天,无聊的YYB想出了一道无聊的题:无聊的数列...(K峰:这题不是傻X题吗) 题目描述 维护一个数列{a[i]} ...

  2. 洛谷 P1438 无聊的数列

    题目背景 无聊的YYB总喜欢搞出一些正常人无法搞出的东西.有一天,无聊的YYB想出了一道无聊的题:无聊的数列...(K峰:这题不是傻X题吗) 题目描述 维护一个数列{a[i]},支持两种操作: 1.1 ...

  3. 洛谷 P1438 无聊的数列 题解

    原题链接 首先,我们考虑用差分解决问题. 用 \(x_i\) 表示原数列,\(a_i = x_i - x_{i-1}\) 那么,先普及一下差分: 如果我们只需要维护区间加值,单点求值的话,你会发现两个 ...

  4. 洛谷P1438 无聊的数列 (线段树+差分)

    变了个花样,在l~r区间加上一个等差数列,等差数列的显著特点就是公差d,我们容易想到用线段树维护差分数组,在l位置加上k,在l+1~r位置加上d,最后在r+1位置减去k+(l-r)*d,这样就是在差分 ...

  5. Luogu P1438无聊的数列

    洛谷 P1438无聊的数列 题目链接 点这里! 题目描述 维护一个数列\(a_i\),支持两种操作: 给出一个长度等于 \(r-l+1\)的等差数列,首项为\(k\) 公差为\(d\) 并将它对应加到 ...

  6. P1438 无聊的数列 (差分+线段树)

    题目 P1438 无聊的数列 解析: 先考虑修改,用差分的基本思想,左端点加上首项\(k\),修改区间\((l,r]\)内每个数的差分数组都加上公差\(d\),最后的\(r+1\)再减去\(k+(r- ...

  7. P1438 无聊的数列

    P1438 无聊的数列 链接 分析: 等差数列可加,首项相加,公差相加. 代码: #include<cstdio> #include<algorithm> #include&l ...

  8. [luogu P1438] 无聊的数列

    [luogu P1438] 无聊的数列 题目背景 无聊的YYB总喜欢搞出一些正常人无法搞出的东西.有一天,无聊的YYB想出了一道无聊的题:无聊的数列...(K峰:这题不是傻X题吗) 题目描述 维护一个 ...

  9. 洛谷.2042.[NOI2005]维护数列(Splay)

    题目链接 2017.12.24 第一次写: 时间: 2316ms (1268ms) 空间: 19.42MB (19.5MB)(O2) 注:洛谷测的时间浮动比较大 /* 插入一段数:将这些数先单独建一棵 ...

随机推荐

  1. ArcGIS API for JavaScript 4.2学习笔记[20] 使用缓冲区结合Query对象进行地震点查询【重温异步操作思想】

    这个例子相当复杂.我先简单说说这个例子是干啥的. 在UI上,提供了一个下拉框.两个滑动杆,以确定三个参数,使用这三个参数进行空间查询.这个例子就颇带空间查询的意思了. 第一个参数是油井类型,第二个参数 ...

  2. Android为TV端助力 关于4.0之后不能直接获取SD卡外部存储路径的问题

    Environment.getExternalStorageDirectory()是Android 2.x时代的产物,那时Android主流设备只有很小的内置存储器,然后都会外置一张sd卡,那时这个方 ...

  3. Android相机启动crash错误排查

    一个Android的用到相机的service程序,在比较少的情况下会出现在系统启动时crash.log显示是在调用ACameraDevice_createCaptureSession时返回错误ACAM ...

  4. ASP.NET Core 入门教程 5、ASP.NET Core MVC 视图传值入门

    一.前言 1.本教程主要内容 ASP.NET Core MVC 视图引擎(Razor)简介 ASP.NET Core MVC 视图(Razor)ViewData使用示例 ASP.NET Core MV ...

  5. Python第七天 函数 函数参数 函数里的变量 函数返回值 多类型传值 函数递归调用 匿名函数 内置函数

    Python第七天   函数  函数参数   函数里的变量   函数返回值  多类型传值     函数递归调用   匿名函数   内置函数 目录 Pycharm使用技巧(转载) Python第一天   ...

  6. MySQL 执行计划中Extra(Using where,Using index,Using index condition,Using index,Using where)的浅析

      关于如何理解MySQL执行计划中Extra列的Using where.Using Index.Using index condition,Using index,Using where这四者的区别 ...

  7. 深入理解Mysql索引的底层数据结构 B+ Tree (2)

    sql查询 explain的详细用法 操作时间:寻道时间+旋转时间 引入索引:采用二叉树结构 把第二列做为索引生成二叉树结构,此时查询89 只做了两次io操作 但是mysql 为什么不用二叉树作为底层 ...

  8. C#-this关键字的功能之扩展方法

    目录 1. 简介 2. 简单实例 3. 细节说明 1. 简介 我们的方法都是与声明他的类的相关联(我们现在写的各个方法都是在类中定义,所以我们调用方法都是用该方法所属类的实体对象调用). 在C#3.0 ...

  9. c/c++ 多线程 绕过mutex的保护

    多线程 绕过mutex的保护 mutex,能够解决线程安全的问题,但它不是万能的.下面的例子虽然使用了mutex,但是恶意注入了一个外部函数,导致把被mutex保护的双向链表,让一个外部的指针指向了, ...

  10. EXTJS的使用

    最近一段时间一直使用Extjs作为前端,通过HTTP与.net后端进行交互,今天总结一下EXTJS,方便以后复习. 1.概念: ExtJS可以用来开发RIA也即富客户端的AJAX应用,是一个用java ...