区间变成等差数列(线段树)
链接: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
说明
第一次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; } } }