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

链接: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;
        }
    }
} 
 
原文地址:https://www.cnblogs.com/lipu123/p/14279522.html