洛谷P1438 无聊的数列

博客食用更佳bossbaby's blog

思路

差分

一看是等差数列,我们就可以知道用差分
每次加等差数列就是区间加
最后区间求和(前缀和)

线段树

区间加和求和可以用线段树做

树状数组

也可以用树状数组做(可惜我不想写不会)

代码

#include <bits/stdc++.h>
#define MAXN 10000100
#define LL long long
#define lid (id<<1)
#define rid (id<<1|1)
using namespace std;
int n,m;
int s[MAXN],su[MAXN];
struct SEG{
    LL lazy,l,r,sum;
}tr[MAXN<<2];
void pushnow(LL id,LL v){
    tr[id].sum+=(tr[id].r-tr[id].l+1)*v;
    tr[id].lazy+=v;
}
void pushdown(LL id){
    if(tr[id].lazy){
        pushnow(lid,tr[id].lazy);
        pushnow(rid,tr[id].lazy);
        tr[id].lazy=0;
    }
}
void pushup(LL id){
    tr[id].sum=tr[lid].sum+tr[rid].sum;
}
void build(LL id,LL l,LL r){
    tr[id].l=l;tr[id].r=r;
    if(l==r){
        tr[id].sum=0;
        tr[id].lazy=0;
        return;
    }
    LL mid=(l+r)>>1;
    build(lid,l,mid);
    build(rid,mid+1,r);
    pushup(id);
}
void update(LL id,LL l,LL r,LL v){
    if(l<=tr[id].l&&r>=tr[id].r){
        pushnow(id,v);
        return;
    }
    pushdown(id);
    LL mid=(tr[id].l+tr[id].r)>>1;
    if(l<=mid)
        update(lid,l,r,v);
    if(r>mid)
        update(rid,l,r,v);
    pushup(id);
}
LL query(LL id,LL l,LL r){
    if(l<=tr[id].l&&r>=tr[id].r)
        return tr[id].sum;
    pushdown(id);
    LL mid=(tr[id].l+tr[id].r)>>1;
    LL ans=0;
    if(l<=mid)
        ans+=query(lid,l,r);
    if(r>mid)
        ans+=query(rid,l,r);
    return ans;
}//线段树
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>s[i];
    build(1,1,n);
    for(int i=1;i<=m;i++){
        int opt;
        cin>>opt;
        if(opt==1){
            int L,R,K,D;
            cin>>L>>R>>K>>D;
            update(1,L,L,K);
            if(R>L)update(1,L+1,R,D);
            int N=(R-L+1);
            if(R<n)update(1,R+1,R+1,-(K+(N-1)*D));
        }//差分区间加
        else{
            int wq;
            cin>>wq;
            cout<<(s[wq]+query(1,1,wq))<<endl;
        }//操作,每次最后输出时再把输入数据加上,避免预处理
    }
    return 0;
}
posted @ 2019-05-30 20:35  bossbaby  阅读(201)  评论(0编辑  收藏  举报