Luogu1438 无聊的数列(单点查询)&&加强版(区间查询)
题目链接:戳我
线段树中差分和前缀和的应用
其实对于加上等差数列的操作我们可以分成这样三步——
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 无聊的数列(单点查询)&&加强版(区间查询)的更多相关文章
- LUOGU1438无聊的数列
区间加等差数列单点查询 思路: 差分,通过树状数组修改,然后保存两个数组,一个存公差,一个存和 然后正常操作即可 在学校潦草写的很潦草啦 代码如下: #include<cstdio> #i ...
- luogu1438无聊的数列(区间加等差数列,求一个数的和)
QAQ一道线段树好题 题目大意: 给定一个有n个数的数列,共m种操作,有两种操作 \(1\ l\ r\ k\ d\)表示将\(a[l]\)~\(a[r]\)的数加一个以k为首相,d为公差 \(2\ x ...
- [luogu1438]无聊的数列
考虑令$b_{i}=a_{i+1}-a_{i}$,那么1操作相当于对L加上K,对(L,R]区间加上D,对R+1减去K+(R-L)*D,然后询问区间和即可 1 #include<bits/stdc ...
- Libre OJ 130、131、132 (树状数组 单点修改、区间查询 -> 区间修改,单点查询 -> 区间修改,区间查询)
这三题均可以用树状数组.分块或线段树来做 #130. 树状数组 1 :单点修改,区间查询 题目链接:https://loj.ac/problem/130 题目描述 这是一道模板题. 给定数列 a[1] ...
- LOJ #6283. 数列分块入门 7-分块(区间乘法、区间加法、单点查询)
#6283. 数列分块入门 7 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 2 题目描述 给出 ...
- LOJ #6282. 数列分块入门 6-分块(单点插入、单点查询、数据随机生成)
#6282. 数列分块入门 6 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 1 题目描述 给出 ...
- LOJ #6277. 数列分块入门 1-分块(区间加法、单点查询)
#6277. 数列分块入门 1 内存限制:256 MiB时间限制:100 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 2 题目描述 给出 ...
- 洛谷P1438 无聊的数列 [zkw线段树]
题目传送门 无聊的数列 题目背景 无聊的YYB总喜欢搞出一些正常人无法搞出的东西.有一天,无聊的YYB想出了一道无聊的题:无聊的数列...(K峰:这题不是傻X题吗) 题目描述 维护一个数列{a[i]} ...
- [luogu P1438] 无聊的数列
[luogu P1438] 无聊的数列 题目背景 无聊的YYB总喜欢搞出一些正常人无法搞出的东西.有一天,无聊的YYB想出了一道无聊的题:无聊的数列...(K峰:这题不是傻X题吗) 题目描述 维护一个 ...
随机推荐
- Django框架之模板语法【转载】
Django框架之模板语法 一.什么是模板? 只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板. 二.模板语法分类 一.模板语法之变量:语法为 {{ }}: 在 Django ...
- 使用python读取大文件
python中读取数据的时候有几种方法,无非是read,readline,readlings和xreadlines几种方法,在几种方法中,read和xreadlines可以作为迭代器使用,从而在读取大 ...
- Delphi7 [Fatal Error] ClassPas.pas(8): File not found: 'DesignIntf.dcu'
Delphi7 [Fatal Error] ClassPas.pas(8): File not found: 'DesignIntf.dcu' Add path to Project>Optio ...
- 深入了解 JPA
转载自:http://www.cnblogs.com/crawl/p/7703679.html 前言:谈起操作数据库,大致可以分为几个阶段:首先是 JDBC 阶段,初学 JDBC 可能会使用原生的 J ...
- UNITY 复制对象后局部坐标和世界坐标的变化问题
void Start () { var pgo = transform.Find ("Button").gameObject; obtn = Instantiate (pgo); ...
- centos7 配置dns服务器
yum install bind ----------------------------------------------------------------------------------- ...
- LevelDB Log文件
[LevelDB Log文件] log文件在LevelDb中的主要作用是系统故障恢复时,能够保证不会丢失数据.因为在将记录写入内存的Memtable之前,会先写入Log文件,这样即使系统发生故障,Me ...
- FluentValidation 模型验证
FluentValidation 是 .NET 下的模型验证组件,和 ASP.NET MVC 基于Attribute 声明式验证的不同处,其利用表达式语法链式编程,使得验证组件与实体分开.正如 Flu ...
- 利用WKWebView实现js与OC交互注意事项
最近在写一些关于wkwebview的一些代码,发现了几点心得,记录一下. 1.js调用OC 我是利用wkwebview进行的开发实现,主要代码有三部分 1.向config注入OC对象 [config. ...
- 配置yum源方法,以及失效时的处理
正常方法如下: step1: 备份原CentOS-Base.repo 文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-B ...