做题记录整理线段树1 P1438 无聊的数列(2022/9/19)

P1438 无聊的数列

一眼差分

原序列:0 0 0 0 0 0
差分序列:0 0 0 0 0 0
等差序列:2 4 6 8 10
加上等差数列后的序列:1 3 5 7 9 0
然后差分:1 2 2 2 2 -9

可以发现,首项所在的位置+k,其他位置+d,最后再全部剪掉就出来了

顺带一提,如果用树状数组应该会快一倍

#include<bits/stdc++.h>
using namespace std;
#define for1(i,a,b) for(ll i = a;i <=b;i++)
#define ll long long
ll n,a[500000],m,x,y,ji;
struct node{
    ll l;
    ll r;
    ll lan;
    ll zhi;
}s[500000*4];

void build(ll q,ll l,ll r)
{
    s[q].lan=0;s[q].l=l;s[q].r=r;
    if(l==r)
    {
        s[q].zhi=a[l];
        return ;
    }
    ll mid = (l+r)/2;
    build(q*2,l,mid);
    build(q*2+1,mid+1,r);
    s[q].zhi=s[q*2].zhi+s[q*2+1].zhi;
}

void chuan(ll q)
{
    if(s[q].lan!=0)
    {
    s[q*2].zhi+=s[q].lan*(s[q*2].r-s[q*2].l+1); 
    s[q*2+1].zhi+=s[q].lan*(s[q*2+1].r-s[q*2+1].l+1);
    s[q*2].lan+=s[q].lan;
    s[q*2+1].lan+=s[q].lan;
    s[q].lan = 0; 
}
}
void xg(ll q,ll l,ll r,ll k)
{
    ll mid = (s[q].l+s[q].r)/2;
    if(s[q].l>=l&&s[q].r<=r)
    {
        s[q].zhi+=(s[q].r-s[q].l+1)*k;
        s[q].lan+=k;
        return ;
    }
    chuan(q);
    if(l<=mid) xg(q*2,l,r,k);
    if(r>mid) xg(q*2+1,l,r,k);
    s[q].zhi=s[q*2].zhi+s[q*2+1].zhi; 
}

ll qh(ll q,ll l,ll r)

{
    ll mid = (s[q].l+s[q].r)/2;
    if(s[q].l>=l&&s[q].r<=r)
    {
        return s[q].zhi;
    }
    chuan(q);
    ll ans=0;
    if(l<=mid) ans+=qh(q*2,l,r);
    if(r>mid) ans+=qh(q*2+1,l,r);
    return ans;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for1(i,1,n)scanf("%lld",&a[i]);
    for(int i=n-1;i>0;i--)
        a[i+1]=a[i+1]-a[i];
    build(1,1,n);
    ll k,d;
    for1(i,1,m)
    {
        scanf("%d",&ji);
        if(ji==1)
        {
            scanf("%d%d%lld%lld",&x,&y,&k,&d);
            xg(1,x,x,k);
            if(x+1<=y)
            xg(1,x+1,y,d);
            if(y+1<=n) 
            xg(1,y+1,y+1,-(k+(y-x)*d));
        }
        else{
            scanf("%lld",&x);
            printf("%lld\n",qh(1,1,x));
        }
    }
    return 0;
 } 
posted @ 2022-09-19 22:23  yyx525jia  阅读(21)  评论(0)    收藏  举报