【洛谷】P1438 无聊的数列


题目大意

1、多次对于区间加上一个等差数列,参数为l,r,k,d,表示首项为k,公差为d,将一个长度r-l+1的等差数列加到区间l..r上
2、询问一个值a[i]


解法

要加上一个等差数列,很容易想到差分,因此将题目简化至下

1、将a[l]加上k;
2、将a[l+1..r]加上d;
3、将a[r+1]-[(r-l)*d+k].

而查询的a[x]的操作随之变为
求∑a[1..x]

于是这道题就是裸差分线段树了,注意线段树细节的问题,还有update之前判断边界问题,即
1、r>l(l+1..r加上d)
2、r<n(r+1减去一些东西)


代码

#include<bits/stdc++.h>
#define lc root<<1
#define rc root<<1|1
#define LL long long
#define maxn 100010
using namespace std;
struct Tree
{
    int left,right;
    LL sum,lazy;
}tree[maxn*4];
int x[maxn],a[maxn];
int n,m;
inline int read()
{
    char ch=getchar();int x=0,f=1;
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void pushup(int root)
{
    tree[root].sum=(LL)tree[lc].sum+tree[rc].sum;
}
inline void build(int root,int l,int r)
{
    tree[root].left=l;tree[root].right=r;tree[root].lazy=0;
    if (l==r)
    {
        tree[root].sum=a[l];
        return;
    }
    int mid=l+r>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    pushup(root);
}
inline void pushdown(int root)
{
    tree[lc].lazy+=tree[root].lazy;tree[rc].lazy+=tree[root].lazy;
    tree[lc].sum+=(LL)(tree[lc].right-tree[lc].left+1)*tree[root].lazy;
    tree[rc].sum+=(LL)(tree[rc].right-tree[rc].left+1)*tree[root].lazy;
    tree[root].lazy=0;
}
inline void update(int root,int l,int r,LL delta)
{
    if (tree[root].left>=l && tree[root].right<=r)
    {
        tree[root].sum+=(LL)(tree[root].right-tree[root].left+1)*delta;
        tree[root].lazy+=delta;
        return;
    }
    if (tree[root].lazy) pushdown(root);
    int mid=tree[root].left+tree[root].right>>1;
    if (l<=mid) update(lc,l,r,delta);
    if (mid<r)  update(rc,l,r,delta);
    pushup(root);
}
inline LL query(int root,int l,int r)
{
    if (tree[root].left>=l && tree[root].right<=r) return tree[root].sum;
    if (tree[root].lazy) pushdown(root);
    int mid=tree[root].left+tree[root].right>>1;LL ans=0;
    if (l<=mid) ans+=query(lc,l,r);
    if (mid<r)  ans+=query(rc,l,r);
    return ans;
}
int main()
{
    n=read();m=read();
    for (int i=1;i<=n;i++)
    {
        x[i]=read();
        a[i]=x[i]-x[i-1];//求差分数组
    }
    build(1,1,n);
    for (int i=1;i<=m;i++)
    {
        int p=read();
        if (p==1)
        {
            int l=read(),r=read(),k=read(),d=read();
            update(1,l,l,k);//首项加上k
            if (r>l) update(1,l+1,r,d);//l+1..r加上d
            if (r<n) update(1,r+1,r+1,-(k+(LL)(r-l)*d));
            //修改第r+1项
        }else 
        {
            int w=read();
            printf("%lld\n",query(1,1,w));//求∑a[1..x]
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cyw_lyr/article/details/78577421
今日推荐