luogu P1438 无聊的数列

思路

区间\(L\)\(R\)内加等差数列
已知首项为\(K\),公差为\(D\)
那么每一位加的数值为
\[K+(i-L)*D(L<=i<=R)\]
\[K+i*D-L*D(L<=i<=R)\]
\[K-L*D+i*D(L<=i<=R)\]
我们可以分别加一下\(K-L*D\)\(i*D\)
前者可以算出来,直接区间加就可以
后者的话,先维护一下\([L,R]\)内的下标和
结合律用一下,加上R*下标和就行了

update

修改的时候在区间\([L,R]\)内的贡献为
\[(K-L*D)*(R-L+1)+\sum_{L}^{R}*D\]

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define ls rt<<1
#define rs rt<<1|1
#define ll long long
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn = 1e5 + 7;
int read() {
    int x = 0, f = 1; char s = getchar();
    for (; s < '0' || s > '9'; s = getchar()) if (s == '-') f = -1;
    for (; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0';
    return x * f;
}
struct node {
    int l,r,size;
    ll ans,lazy1,tot,lazy2;
}e[maxn<<2];
int n,m,a[maxn];
void pushup(int rt) {
    e[rt].ans=e[ls].ans+e[rs].ans;
}
void pushdown(int rt) {
    if(e[rt].lazy1) {
        e[ls].ans+=e[ls].size*e[rt].lazy1;
        e[rs].ans+=e[rs].size*e[rt].lazy1;
        e[ls].lazy1+=e[rt].lazy1;
        e[rs].lazy1+=e[rt].lazy1;
        e[rt].lazy1=0;
    }
    if(e[rt].lazy2) {
        e[ls].ans+=e[ls].tot*e[rt].lazy2;
        e[rs].ans+=e[rs].tot*e[rt].lazy2;
        e[ls].lazy2+=e[rt].lazy2;
        e[rs].lazy2+=e[rt].lazy2;
        e[rt].lazy2=0;
    }
}
void build(int l,int r,int rt) {
    e[rt].l=l,e[rt].r=r,e[rt].size=r-l+1;
    if(l==r) {
        e[rt].tot=l;
        e[rt].ans=a[l];
        return;
    }
    int mid=(e[rt].l+e[rt].r)>>1;
    build(l,mid,ls);
    build(mid+1,r,rs);
    pushup(rt);
    e[rt].tot=e[ls].tot+e[rs].tot;
}
void modfity_1(int L,int R,ll k,int rt) { // 区间加
    if(L<=e[rt].l&&e[rt].r<=R) {
        e[rt].ans+=k*e[rt].size;
        e[rt].lazy1+=k; 
        return;
    }
    pushdown(rt);
    int mid=(e[rt].l+e[rt].r)>>1;
    if(L<=mid) modfity_1(L,R,k,ls);
    if(R>mid) modfity_1(L,R,k,rs);
    pushup(rt);
}
void modfity_2(int L,int R,ll k,int rt) { // 区间i*k
    if(L<=e[rt].l&&e[rt].r<=R) {
        e[rt].ans+=k*e[rt].tot;
        e[rt].lazy2+=k;
        return;
    }
    pushdown(rt);
    int mid=(e[rt].l+e[rt].r)>>1;
    if(L<=mid) modfity_2(L,R,k,ls);
    if(R>mid) modfity_2(L,R,k,rs);
    pushup(rt); 
}
ll query(int L,int rt) {
    if(e[rt].l==e[rt].r) {
        return e[rt].ans;
    }
    pushdown(rt);
    int mid=(e[rt].l+e[rt].r)>>1;
    if(L<=mid) return query(L,ls);
    else return query(L,rs);
}
int main() {
    n=read(),m=read();
    FOR(i,1,n) a[i]=read();
    build(1,n,1);
    FOR(i,1,m) {
        int pd=read();
        if(pd==1) {
            int l=read(),r=read(),k=read(),d=read();
            modfity_1(l,r,k-l*d,1);
            modfity_2(l,r,d,1);
        } else {
            int x=read();
            printf("%lld\n",query(x,1));
        }
    }
    return 0;
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
06-08 10:39
上周一,mentor&nbsp;直接把我拉到会议室里边,给我说今天的团建我就不参与了。还没有来得及问缘由,mentor&nbsp;就说,因为没有实习生的预算。最招的是下午有个那种六一下午茶活动,就有各种点心零食什么的,我本人嗓子不舒服(是真不舒服就没去)然后mentor又回来给我说晚上团建让我去,说领导特意申请了,让我千万得去。我此时内心:哎不行你来我家吃饭呗?我这吃饭不用走审批,多双筷子的事。团建大概三十多人。同时在会议室告诉我,就是不要再进行什么创新,老实回归于业务。(Ps一句招的岗位是&nbsp;AI+测试。)实则进来全是点点点,因为我之前有相关的实习经验,然后landing了两天,直接就开始接手业务了。其实没有太大的波动。因为我觉得都是在情理之中。然后最绷不住的来了。mentor又说我的leader让我不要待在组里群里边。说群里发周报什么的怕我看到。我说实话,上过班的都知道,这玩意就是糊弄鬼的,你求着我看我都不想看。我当时真的感觉一下子就被推到边缘了。,和我前一家公司不一样的是,它这里边所有的实习生都是写的外包人员。。从一开始也没有什么工牌之类的。这家公司并不小。上个周五提离职,mentor&nbsp;还以为觉得是我每天做&nbsp;dirty&nbsp;work&nbsp;受不了。感觉他已经猜到我要提离职了的,而且是很早就猜到了。我也没有过多解释,留下了一句,与个人职业生涯规划不符,就走了。从入职到现在,总共是第三个星期。上周五走出公司的那一刻,我真的觉得前所未有的轻松。ps一句周四的时候也是通过另外一家公司的三面,世上自有留人处。
实习生的蛐蛐区
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务