洛谷P1438 无聊的数列

题目背景

无聊的YYB总喜欢搞出一些正常人无法搞出的东西。有一天,无聊的YYB想出了一道无聊的题:无聊的数列。。。(K峰:这题不是傻X题吗)

题目描述

维护一个数列{a[i]},支持两种操作:

1、1 L R K D:给出一个长度等于R-L+1的等差数列,首项为K,公差为D,并将它对应加到a[L]~a[R]的每一个数上。即:令a[L]=a[L]+K,a[L+1]=a[L+1]+K+D,

a[L+2]=a[L+2]+K+2D……a[R]=a[R]+K+(R-L)D。

2、2 P:询问序列的第P个数的值a[P]。

输入输出格式

输入格式:

第一行两个整数数n,m,表示数列长度和操作个数。

第二行n个整数,第i个数表示a[i](i=1,2,3…,n)。

接下来的m行,表示m个操作,有两种形式:

1 L R K D

2 P 字母意义见描述(L≤R)。

输出格式:

对于每个询问,输出答案,每个答案占一行。

输入输出样例

输入样例#1: 
5 2
1 2 3 4 5
1 2 4 1 2
2 3
输出样例#1: 
6

说明

数据规模:

0≤n,m≤100000

|a[i]|,|K|,|D|≤200

线段树+差分

线段树每一个叶子结点存这一项与前一项的差。

区间 [ l , r ] 修改:l 加上k,[ l+1 , r ] 都加上 d,r+1 减去 ( ( r - l ) * d + k )。

求某一位置 x 的值:求线段树 [ 1 , x ] 区间和。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define SIGN(x) a[x].c
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1);
#define MAXN 100010
using namespace std;
int n,m,val[MAXN];
struct node{
    long long data,c;
    int l,r;
}a[MAXN<<2];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline void pushup(int rt){
    DATA(rt)=DATA(LSON)+DATA(RSON);
}
inline void pushdown(int rt){
    if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;
    SIGN(LSON)+=SIGN(rt);
    DATA(LSON)+=SIGN(rt)*WIDTH(LSON);
    SIGN(RSON)+=SIGN(rt);
    DATA(RSON)+=SIGN(rt)*WIDTH(RSON);
    SIGN(rt)=0;
}
void buildtree(int l,int r,int rt){
    int mid;
    LSIDE(rt)=l;
    RSIDE(rt)=r;
    if(l==r){
        DATA(rt)=val[l]-val[l-1];
        return;
    }
    mid=l+r>>1;
    buildtree(l,mid,LSON);
    buildtree(mid+1,r,RSON);
    pushup(rt);
}
void update(int l,int r,long long c,int rt){
    int mid;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
        SIGN(rt)+=c;
        DATA(rt)+=c*WIDTH(rt);
        return;
    }
    pushdown(rt);
    mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)update(l,r,c,LSON);
    if(mid<r)update(l,r,c,RSON);
    pushup(rt);
}
long long query(int l,int r,int rt){
    int mid;
    long long ans=0;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
    pushdown(rt);
    mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)ans+=query(l,r,LSON);
    if(mid<r)ans+=query(l,r,RSON);
    return ans;
}
int main(){
    int f,x,y,k,d;
    n=read();m=read();
    val[0]=0;
    for(int i=1;i<=n;i++)val[i]=read();
    buildtree(1,n,1);
    while(m--){
        f=read();x=read();
        if(f==1){
            y=read();k=read();d=read();
            update(x,x,k,1);
            if(x!=y)update(x+1,y,d,1);
            if(y<n)update(y+1,y+1,(-(y-x)*d-k),1);
        }
        if(f==2)printf("%lld\n",query(1,x,1));
    }
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值