1010 区区区间 分块 线段树

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

题目描述

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

操作有两种:

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

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

输入描述:

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

第二行 nnn 个整数,表示序列的初始值 a1,a2,…an(1<=ai<=2e5)a_1,a_2,…a_n(1<=a_i<=2e5)a1,a2,an1<=ai<=2e5

接下来 mmm 行,每行三或四个数字,若第一个数字是 111,则表示操作 111,反之则表示操作 222。

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

输出描述:

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

示例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

分析

问题在于修改区间内的每一个位置的值不是统一的加减,而是有公差的。

可以用lazy 标记维护每个区间的首项,由于公差是固定的,也就知道了区间的尾项,传递下去的时候,也就知道了每一个位置的值。

 

//-------------------------代码----------------------------

#define int ll
const int N = 2e5+10;
int n,m;

struct node {
    int l,r,s,la;
} tr[N<<2];
int a[N];

void push_up(int u) {
    tr[u].s=tr[ul].s+tr[ur].s;
}

void push_down(int u) {
    if(tr[u].la==0)return ;
    tr[ul].la=tr[u].la;tr[ur].la=tr[u].la+tr_len(ul);
    int w=(tr[ul].r-tr[ul].l)+tr[ul].la;
    tr[ul].s=(tr[ul].la+w)*tr_len(ul)/2;
    tr[ur].s=tr[u].s-tr[ul].s;
    tr[u].la=0;
}

void build(int u,int l,int r) {
    tr[u]={l,r,0,0};
    if(l==r){tr[u].s=a[l];return ;}
    build(ul,l,tr_mid);build(ur,tr_mid+1,r);
    push_up(u);
}

void modify(int u,int l,int r,int k) {
    if(tr[u].l>=l&&tr[u].r<=r) {
        tr[u].la=k+(tr[u].l-l);//la维护首项
        int w=(tr[u].r-tr[u].l)+tr[u].la;//尾项
        tr[u].s=(tr[u].la+w)*(tr_len(u))/2;
        return ;
    }
    push_down(u);
    if(l<=tr_mid)modify(ul,l,r,k);
    if(r>tr_mid)modify(ur,l,r,k);
    push_up(u);
}

int query(int u,int l,int r) {
    if(tr[u].l>=l&&tr[u].r<=r)return tr[u].s;
    if(tr[u].l>r||tr[u].r<l)return 0;
    push_down(u);
    return query(ul,l,r)+query(ur,l,r);
}

void solve()
{
    cin>>n>>m;
    fo(i,1,n) cin>>a[i];
    build(1,1,n);
    while(m -- ) {
        int op,l,r;cin>>op>>l>>r;
        if(op == 1) {
            int k;cin>>k;
            modify(1, l, r, k);
        } else {
            cout<<query(1,l,r)<<endl;
        }
    }
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-09 17:04  er007  阅读(47)  评论(0)    收藏  举报