题目链接:戳我

线段树中差分和前缀和的应用

其实对于加上等差数列的操作我们可以分成这样三步——

update(1,1,n,l,l,k);
if(r>l) update(1,1,n,l+1,r,d);
if(r!=n) update(1,1,n,r+1,r+1,-(r-l)*d-k);

然后查询的时候1到当前位置的和就是这个数的值啦!

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MAXN 100010
using namespace std;
int n,m;
int a[MAXN];
struct Node{int l,r,sum,tag;}t[MAXN<<2]; inline int ls(int x){return x<<1;} inline int rs(int x){return x<<1|1;} inline void push_up(int x){t[x].sum=t[ls(x)].sum+t[rs(x)].sum;} inline void solve(int x,int l,int r,int k)
{
t[x].tag+=k;
t[x].sum+=(r-l+1)*k;
} inline void push_down(int x,int l,int r)
{
if(t[x].tag)
{
int mid=(l+r)>>1;
solve(ls(x),l,mid,t[x].tag);
solve(rs(x),mid+1,r,t[x].tag);
t[x].tag=0;
}
} inline void update(int x,int l,int r,int ll,int rr,int k)
{
if(ll<=l&&r<=rr)
{
t[x].sum+=(r-l+1)*k;
t[x].tag+=k;
return;
}
int mid=(l+r)>>1;
push_down(x,l,r);
if(ll<=mid) update(ls(x),l,mid,ll,rr,k);
if(mid<rr) update(rs(x),mid+1,r,ll,rr,k);
push_up(x);
} inline int query(int x,int l,int r,int ll,int rr)
{
int cur_ans=0;
if(ll<=l&&r<=rr) return t[x].sum;
int mid=(l+r)>>1;
push_down(x,l,r);
if(ll<=mid) cur_ans+=query(ls(x),l,mid,ll,rr);
if(mid<rr) cur_ans+=query(rs(x),mid+1,r,ll,rr);
return cur_ans;
} int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
int op,l,r,k,d,p;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d%d",&l,&r,&k,&d);
update(1,1,n,l,l,k);
if(r>l) update(1,1,n,l+1,r,d);
if(r!=n) update(1,1,n,r+1,r+1,-(r-l)*d-k);
}
else
{
scanf("%d",&p);
printf("%d\n",query(1,1,n,1,p)+a[p]);
}
}
return 0;
}

PS:(蒟蒻的一点小想法)

这道题让我们求的是单点查询。。。如果是区间查询呢?

这样我们就别用前缀和来表示这个数了,但是因为等差数列完全满足可加性,还是可以直接上线段树的啊!

下面是代码:(应该是没有什么问题,因为是在大佬的单点查询的代码基础上更改的)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAX 1100000
#define lson (now<<1)
#define rson (now<<1|1)
struct Node
{
int s,lyk,lyd;
void put(int now,int l,int r,int K,int D)
{
int la=(r-l)*D+K;
s+=(K+la)*(r-l+1)/2;
lyk+=K;
lyd+=D;
}
}t[MAX<<2];
int N,M;
int a[MAX];
void pushdown(int now,int l,int r)
{
if(!t[now].lyd&&!t[now].lyk)return;
int mid=(l+r)>>1;
t[lson].put(lson,l,mid,t[now].lyk,t[now].lyd);
t[rson].put(rson,mid+1,r,t[now].lyk+(mid-l+1)*t[now].lyd,t[now].lyd);
t[now].lyd=t[now].lyk=0;
}
void update(int now,int l,int r,int al,int ar,int K,int D)
{
pushdown(now,l,r);
if(l==al&&r==ar){t[now].put(now,l,r,K,D);}
else
{
int la=(ar-al)*D+K;
t[now].s+=(K+la)*(ar-al+1)/2;
int mid=(l+r)>>1;
if(ar<=mid)update(lson,l,mid,al,ar,K,D);
else if(al>mid)update(rson,mid+1,r,al,ar,K,D);
else
{
update(lson,l,mid,al,mid,K,D);
update(rson,mid+1,r,mid+1,ar,K+(mid+1-al)*D,D);
}
}
}
int query(int now,int l,int r,int ll,int rr)
{
int cur_ans=0;
pushdown(now,l,r);
if(ll<=l&&r<=rr) return t[now].s;
int mid=(l+r)>>1;
if(ll<=mid) cur_ans+=query(lson,l,mid,ll,rr);
if(mid<rr) cur_ans+=query(rson,mid+1,r,ll,rr);
return cur_ans;
}
int main()
{
freopen("ce.in","r",stdin);
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++) scanf("%d",&a[i]);
for(int i=1;i<=N;i++) a[i]+=a[i-1];
int opt;
while(M--)
{
scanf("%d",&opt);
if(opt==1)
{
int L,R,K,D;
scanf("%d%d%d%d",&L,&R,&K,&D);
update(1,1,N,L,R,K,D);
}
else
{
int p,q;
scanf("%d%d",&p,&q);
printf("%d\n",query(1,1,N,p,q)+a[q]-a[p-1]);
}
}
return 0;
}

Luogu1438 无聊的数列(单点查询)&&加强版(区间查询)的更多相关文章

  1. LUOGU1438无聊的数列

    区间加等差数列单点查询 思路: 差分,通过树状数组修改,然后保存两个数组,一个存公差,一个存和 然后正常操作即可 在学校潦草写的很潦草啦 代码如下: #include<cstdio> #i ...

  2. luogu1438无聊的数列(区间加等差数列,求一个数的和)

    QAQ一道线段树好题 题目大意: 给定一个有n个数的数列,共m种操作,有两种操作 \(1\ l\ r\ k\ d\)表示将\(a[l]\)~\(a[r]\)的数加一个以k为首相,d为公差 \(2\ x ...

  3. [luogu1438]无聊的数列

    考虑令$b_{i}=a_{i+1}-a_{i}$,那么1操作相当于对L加上K,对(L,R]区间加上D,对R+1减去K+(R-L)*D,然后询问区间和即可 1 #include<bits/stdc ...

  4. Libre OJ 130、131、132 (树状数组 单点修改、区间查询 -> 区间修改,单点查询 -> 区间修改,区间查询)

    这三题均可以用树状数组.分块或线段树来做 #130. 树状数组 1 :单点修改,区间查询 题目链接:https://loj.ac/problem/130 题目描述 这是一道模板题. 给定数列 a[1] ...

  5. LOJ #6283. 数列分块入门 7-分块(区间乘法、区间加法、单点查询)

    #6283. 数列分块入门 7 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 2   题目描述 给出 ...

  6. LOJ #6282. 数列分块入门 6-分块(单点插入、单点查询、数据随机生成)

    #6282. 数列分块入门 6 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 1   题目描述 给出 ...

  7. LOJ #6277. 数列分块入门 1-分块(区间加法、单点查询)

    #6277. 数列分块入门 1 内存限制:256 MiB时间限制:100 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 2   题目描述 给出 ...

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

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

  9. [luogu P1438] 无聊的数列

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

随机推荐

  1. 用 Vue 改造 Bootstrap,渐进提升项目框架

    前言 Vue 横空出世,以迅雷不及掩耳之势横扫前端界,俨然有当年 jQuery 之势.我认为 Vue 成功的关键在于三点: 学习曲线平缓,有点经验的前端基本上一天就能看完文档,然后就可以上手操作. 上 ...

  2. String(byte[] bytes, Charset charset) 和 getBytes() 使用

    转自:https://techbirds.iteye.com/blog/1855960 @Test public void testBytes(){ //字节数 //中文:ISO:1 GBK:2 UT ...

  3. DOCKER windows 7 详细安装教程

    DOCKER windows安装 编者: xiaym 日期:2015年1月20日 排版工具: 马克飞象 QQ: 252536711 DOCKER windows安装 1.下载程序包 2. 设置环境变量 ...

  4. Selection II

    [Selection II] 1.上.下.左.右键可以移动Selection 1个像素.按住Shift键,可以一次移动10个像素. 2.Add Selection模式的快捷键是Shift,Sub Se ...

  5. java基础三 [深入多态,接口和多态](阅读Head First Java记录)

    抽象类和抽象方法 1.抽象类的声明方法,在前面加上抽象类的关键词abstract abstract class canine extends animal{      public void roam ...

  6. ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)

    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var mysql 启动不了 ERROR 2002 ( ...

  7. 745. Prefix and Suffix Search 查找最大index的单词

    [抄题]: Given many words, words[i] has weight i. Design a class WordFilter that supports one function, ...

  8. Git学习笔记-----下载GitHub上某个分支的代码

    在GitHub上的仓库里,往往建有几个分支,如果只是想下载某个分支的代码,怎么办呢? 1.需要知道远程分支的名称,及远程分支所在的Git仓库 2.按下面指令下载 git clone -b 远程分支名称 ...

  9. MVC过滤器实现用户登录验证

    前言当我们访问某个网站的时候需要检测用户是否已经登录(通过Session是否为null),我们知道在WebForm中可以定义一个BasePage类让他继承System.Web.UI.Page,重写它的 ...

  10. Golang之fmt格式“占位符”

    golang的fmt包实现了格式化I/O函数: package main import "fmt" type Human struct { Name string } func m ...