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题吗) 题目描述 维护一个 ...
随机推荐
- Spring集成的Quartz 并发
以前经常在任务调度程序中使用Spring集成的Quartz,这种方式可以用简单的声明式配置即可实现定时任务,并结合了Spring自身的Bean的管理功能,非常方便.配置样本如下: <bean i ...
- opencv_traincascade 训练自己的检测器
2013年08月08日 ⁄ 综合 ⁄ 共 1061字 ⁄ 字号 小 中 大 ⁄ 评论关闭 经过近一个月的工程实战,把自己累积的经验分享给大家,教你如何训练一个收敛的,比opencv自带的data效 ...
- sql 存储过程返回值 变量名
return 语句返回值,前台调用的参数名称为 @RETURN_VALUE
- Spring Boot自动配置
Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...
- Spring cloud @RefreshScope使用
参数 @RestController @RefreshScope public class HomeController { @Value("${foo}") String foo ...
- 学习IIS & MVC的运行原理 (转)
我一直疑惑于以下问题,从客户端发出一个请求,请求到达服务器端是怎样跟iis衔接起来的,而iis又是怎样读取我发布的代码的,并返回服务器上的文件.这其中是怎样的一个处理过程. 1:当你从浏览器中输入一个 ...
- 自定义annotation-----转载
Java从JDK5.0开始便提供了四个meta-annotation用于自定义注解的时候使用,这四个注解为:@Target,@Retention,@Documented 和@Inherited. @T ...
- socket & pipe note
[socket & pipe note] 1.socket类型 2.大小端 3.socketpair 如何创建全双工管道? 直接的办法当然是pipe两次,创建两组管道,但是有没有更简单的呢? ...
- s 销售视图数据
INSERT,需将公司ID匹对到以下EXCEL表 INSERT,需将公司ID匹对到以下EXCEL表 [Public] ConnectString=host="siebel://10.10.0 ...
- Theoretical & Applied Mechanics Letters第2届编委会2015年度第1次全体编委会工作会议纪要(转自力学学会)
2015年7月26日, Theoretical & Applied Mechanics Letters (TAML)第2届编委会在中国科学院力学研究所召开2015年第1次 全体编委工作会议.主 ...