• 区间变成等差数列(线段树)


    链接:https://ac.nowcoder.com/acm/contest/3282/E
    来源:牛客网

    题目描述

    Keven 特别喜欢线段树,他给你一个长度为 n 的序列,对序列进行m 次操作。

    操作有两种:

    1 l r k :表示将下标在 [l,r]区间内的数字替换成 [k,k+1,…,k+r−l]

    2 l r :表示查询区间 [l,r] 的区间和

    输入描述:

    第一行两个整数 n、m,表示序列的长度和操作次数(1<=n,m<=2e5)

    第二行 n 个整数,表示序列的初始值 a1,a2,…an(1<=ai<=2e5)

    接下来 m 行,每行三或四个数字,若第一个数字是 1,则表示操作 1,反之则表示操作 2

    (1<=l<=r<=n,1<=k<=2e5)

    输出描述:

    对于每个操作 2,输出一行一个整数表示区间和。

    示例1

    输入

    复制
    5 5
    1 1 1 1 1
    2 1 5
    1 1 5 1
    2 1 5
    1 1 3 3
    2 1 3

    输出

    复制
    5
    15
    12

    说明

    第一次1操作后,序列是1 2 3 4 5
    第二次1操作后,序列是3 4 5 4 5



    这个一眼看过去要用线段树写,最关键的是懒惰标记怎么传:
    在这里懒惰标记每一段区间的首项,
    那么传懒惰标记的时候就是:
    假如传的是p,那么2*p那一段的首项是等于p的首项的,2*p+1那一段那一段的首项是p的首相加2*P那一段的长度
    if(t[p].lazy){
        t[2*p].lazy=t[p].lazy;//左边的首相不变 
        t[2*p].sum=(2*t[2*p].lazy+t[2*p].r-t[2*p].l)*(t[2*p].r-t[2*p].l+1)/2;//等差数列求和公式 
            
        t[2*p+1].lazy=(t[p].lazy+t[2*p].r-t[2*p].l+1);//右边的首项是=左边的首项+左边的长度 
        t[2*p+1].sum=(2*t[2*p+1].lazy+t[2*p+1].r-t[2*p+1].l)*(t[2*p+1].r-t[2*p+1].l+1)/2;//求和公式 
        t[p].lazy=0;
    }
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+100;
    struct node{
        int l,r;
        ll sum,lazy;
    }t[maxn];
    ll a[maxn];
    void jianshu(int p,int l,int r){
        t[p].l=l,t[p].r=r;
        if(l==r){
            t[p].sum=a[l];
            return ;
        }
        int mid=(l+r)/2;
        jianshu(2*p,l,mid);
        jianshu(2*p+1,mid+1,r);
        t[p].sum=t[2*p].sum+t[2*p+1].sum;
    } 
    void pushdown(int p){
        if(t[p].lazy){
            t[2*p].lazy=t[p].lazy;
            t[2*p].sum=(2*t[2*p].lazy+t[2*p].r-t[2*p].l)*(t[2*p].r-t[2*p].l+1)/2;
            
            t[2*p+1].lazy=(t[p].lazy+t[2*p].r-t[2*p].l+1);
            t[2*p+1].sum=(2*t[2*p+1].lazy+t[2*p+1].r-t[2*p+1].l)*(t[2*p+1].r-t[2*p+1].l+1)/2;
            t[p].lazy=0;
        }
    //    if(t[p].lazy) {
    //        int mid=(t[p].l+t[p].r)/2;
    //        t[p*2].lazy=t[p].lazy;
    //        t[p*2+1].lazy=t[p].lazy+mid-t[p].l+1;
    //        t[p*2].sum=(t[p*2].lazy*2+(mid-t[p].l))*(mid-t[p].l+1)/2;
    //        t[p*2+1].sum=((t[p*2+1].lazy)*2+(t[p].r-mid-1))*(t[p].r-mid)/2;
    //        t[p].lazy=0;
    //    }
    }
    void update(int p,int l,int r,ll k){
        int L=t[p].l,R=t[p].r;
        if(l<=L&&R<=r){
            t[p].lazy=(k+t[p].l-l);
            t[p].sum=(2*t[p].lazy+t[p].r-t[p].l)*(t[p].r-t[p].l+1)/2;
            return ;
        }
        int mid=(L+R)/2;
        pushdown(p);
        if(l<=mid){
            update(2*p,l,r,k);
        }
        if(r>mid){
            update(2*p+1,l,r,k);
        }
        t[p].sum=t[2*p].sum+t[2*p+1].sum;
    }
    ll query(int p,int l,int r){
        int L=t[p].l,R=t[p].r;
        if(l<=L&&R<=r){
            return t[p].sum;
        }
        int mid=(t[p].l+t[p].r)/2;
        pushdown(p);
        ll ans=0;
        if(l<=mid){
            ans+=query(2*p,l,r);
        }
        if(r>mid){
            ans+=query(2*p+1,l,r);
        }
        return ans;
    } 
    int main(){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]); 
        }
        jianshu(1,1,n);
        int op,x,y;
        ll k;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&op,&x,&y);
            if(op==1){
                scanf("%lld",&k);
                update(1,x,y,k);
            }
            else{
                ll ans=query(1,x,y);
                cout<<ans<<endl;
            }
        }
    } 
     
  • 相关阅读:
    LeetCode347 前k个高频元素
    剑指42 连续字数租的最大和
    hdu1540
    hdu4553 两棵线段树
    cdq分治
    负环
    最短路
    差分约束系统
    hdu3308
    hdu5862 树状数组+扫描线+离散化
  • 原文地址:https://www.cnblogs.com/lipu123/p/14279522.html
Copyright © 2020-2023  润新知