洛谷P1438 无聊的数列
博客食用更佳bossbaby's blog
思路
差分
一看是等差数列,我们就可以知道用差分
每次加等差数列就是区间加
最后区间求和(前缀和)
线段树
区间加和求和可以用线段树做
树状数组
也可以用树状数组做(可惜我不想写不会)
代码
#include <bits/stdc++.h>
#define MAXN 10000100
#define LL long long
#define lid (id<<1)
#define rid (id<<1|1)
using namespace std;
int n,m;
int s[MAXN],su[MAXN];
struct SEG{
LL lazy,l,r,sum;
}tr[MAXN<<2];
void pushnow(LL id,LL v){
tr[id].sum+=(tr[id].r-tr[id].l+1)*v;
tr[id].lazy+=v;
}
void pushdown(LL id){
if(tr[id].lazy){
pushnow(lid,tr[id].lazy);
pushnow(rid,tr[id].lazy);
tr[id].lazy=0;
}
}
void pushup(LL id){
tr[id].sum=tr[lid].sum+tr[rid].sum;
}
void build(LL id,LL l,LL r){
tr[id].l=l;tr[id].r=r;
if(l==r){
tr[id].sum=0;
tr[id].lazy=0;
return;
}
LL mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
pushup(id);
}
void update(LL id,LL l,LL r,LL v){
if(l<=tr[id].l&&r>=tr[id].r){
pushnow(id,v);
return;
}
pushdown(id);
LL mid=(tr[id].l+tr[id].r)>>1;
if(l<=mid)
update(lid,l,r,v);
if(r>mid)
update(rid,l,r,v);
pushup(id);
}
LL query(LL id,LL l,LL r){
if(l<=tr[id].l&&r>=tr[id].r)
return tr[id].sum;
pushdown(id);
LL mid=(tr[id].l+tr[id].r)>>1;
LL ans=0;
if(l<=mid)
ans+=query(lid,l,r);
if(r>mid)
ans+=query(rid,l,r);
return ans;
}//线段树
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>s[i];
build(1,1,n);
for(int i=1;i<=m;i++){
int opt;
cin>>opt;
if(opt==1){
int L,R,K,D;
cin>>L>>R>>K>>D;
update(1,L,L,K);
if(R>L)update(1,L+1,R,D);
int N=(R-L+1);
if(R<n)update(1,R+1,R+1,-(K+(N-1)*D));
}//差分区间加
else{
int wq;
cin>>wq;
cout<<(s[wq]+query(1,1,wq))<<endl;
}//操作,每次最后输出时再把输入数据加上,避免预处理
}
return 0;
}