洛谷 P1438 无聊的数列
传送门:洛谷 P1438 无聊的数列
算法分析:为\([l,r]\)加上首项为\(k\),公差为\(d\)的等差数列,在差分上表现为:
\[\begin{cases}
sum[l]=sum[l]+k\\
sum[i]=sum[i]+d,i\in(l,r]\\
sum[r+1]=sum[r+1]-(k+(r-l)\times d)\\
\end{cases}
\]
其中 \(sum\) 为差分数组,查询 \(p\) 的答案 \(ans=a[p]+\sum_{i=1}^{p}sum[i]\)
显然,上述操作是线段树区间修改和求和的步骤
#include<iostream>
#include<cstdio>
#define maxN 100010
#define in(x) x=read()
#define ls k<<1
#define rs k<<1 | 1
#define mid ((l+r)>>1)
using namespace std;
typedef long long rd;
typedef long long ll;
ll sum[maxN*4+1],v[maxN*4+1];
int n,m,op,x,y,a[maxN+1],d,k;
inline rd read();
void pushdown(int,int,int),pushup(int);
ll query(int,int,int,int,int);
void update(int,int,int,int,int,int);
int main()
{
in(n); in(m);
for(int i=1;i<=n;i++) in(a[i]);
for(int i=1;i<=m;i++)
if(read()==1)
{
in(x); in(y); in(k); in(d);
update(1,1,n,x,x,k);
update(1,1,n,x+1,y,d);
update(1,1,n,y+1,y+1,-k-(y-x)*d);
}
else
{
in(x);
printf("%lld\n",query(1,1,n,1,x)+a[x]);
}
return 0;
}
void pushup(int k) {sum[k]=sum[ls]+sum[rs];}
void pushdown(int k,int l,int r)
{
v[ls]+=v[k]; v[rs]+=v[k];
sum[ls]+=(mid-l+1)*v[k];
sum[rs]+=(r-mid)*v[k];
v[k]=0;
}
void update(int k,int l,int r,int ql,int qr,int u)
{
if(ql<=l && r<=qr)
{
sum[k]+=u*(r-l+1);
v[k]+=u; return;
}
if(v[k]) pushdown(k,l,r);
if(ql<=mid) update(ls,l,mid,ql,qr,u);
if(qr>mid) update(rs,mid+1,r,ql,qr,u);
pushup(k);
}
long long query(int k,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr) return sum[k];
long long ans=0;
if(v[k]) pushdown(k,l,r);
if(ql<=mid) ans+=query(ls,l,mid,ql,qr);
if(qr>mid) ans+=query(rs,mid+1,r,ql,qr);
return ans;
}
inline rd read()
{
rd num=0,f=1;
char ch=getchar();
while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if(ch=='-') {ch=getchar(); f=-1;}
while(ch>='0' && ch<='9')
{
num=num*10+ch-'0';
ch=getchar();
}
return num*f;
}