题面
分析
等差数列!等差数列!等差数列!
等差!等差!等差!
差分!差分!差分!
就这样喽
假设有一数列a1,a2,a3,a4…a10,对其加上等差数列t,t+d,t+2d…t+6d,(L=2,R=8)
将其构造成差分数组,如中间部分所示,很明显可以看到差分数组的绿色部分只需要全部加上d,第L项加上t,第R+1项加上
就可以维护好整个差分数组且满足差分数组的前缀和性质了
于是本题其实就是用线段树去维护差分数组的区间和
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(int i=start;i<=end;i++)
#define clean(arry,num); memset(arry,num,sizeof(arry));
int n,m;
const int maxn=100000+10;
const int maxm=100000+10;
int d[maxn];
int sum[maxn<<2];
int lazy[maxn<<2];
inline int read()
{
int ans=0;bool neg=false;char r=getchar();
while(r>'9'||r<'0'){if(r=='-')neg=true;r=getchar();}
while(r>='0'&&r<='9'){ans=ans*10+r-'0';r=getchar();}
return (neg)?-ans:ans;
}
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int len)
{
if(!lazy[rt])return;
lazy[rt<<1]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
sum[rt<<1]+=lazy[rt]*(len-((len)>>1));//优先级问题!不能写len-len>>1
sum[rt<<1|1]+=lazy[rt]*((len)>>1);
lazy[rt]=0;
}
void buildtree(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=d[l];
return;
}
int m=(l+r)>>1;
buildtree(l,m,rt<<1);
buildtree(m+1,r,rt<<1|1);
pushup(rt);
}
int query(int ql,int qr,int nl,int nr,int rt)
{
if(ql<=nr&&nr<=qr)return sum[rt];
pushdown(rt,nr-nl+1);
int m=(nl+nr)/2;
int ans=0;
if(m>=ql)ans+=query(ql,qr,nl,m,rt<<1);
if(qr>m)ans+=query(ql,qr,m+1,nr,rt<<1|1);
return ans;
}
void update(int ul,int ur,int nl,int nr,int num,int rt)
{
if(ul<=nl&&nr<=ur)
{
lazy[rt]+=num;
sum[rt]+=(nr-nl+1)*num;
return;
}
pushdown(rt,nr-nl+1);
int m=(nl+nr)/2;
if(ul<=m)update(ul,ur,nl,m,num,rt<<1);
if(m<ur)update(ul,ur,m+1,nr,num,rt<<1|1);
pushup(rt);
}
int main()
{
n=read();m=read();
int numfront=0;
loop(i,1,n)
{
int aa=read();
d[i]=aa-numfront;
numfront=aa;
}
buildtree(1,n,1);
loop(i,1,m)
{
int op=read();
if(op==2)
{
int r=read();
printf("%d\n",query(1,r,1,n,1));
}
else if(op==1)
{
int l,r,k,d;l=read();r=read();k=read();d=read();
update(l,l,1,n,k,1);
if(l!=r)update(l+1,r,1,n,d,1);//小心越界!!!l+1不能大于r,r+1不能大于n!!!!
if(r!=n)update(r+1,r+1,1,n,-k-(r-l)*d,1);
}
}
return 0;
}
学到的东西
都在代码里了~~~~