2022春每日一题:Day 26



题目:无聊的数列

区间增加等差序列,似乎不好维护,等差等差,那就差分呗,单点查询,更加肯定,直接差分,每次加了一个等差序列容易发现只需要对应的差分数组a[l]+=k,a[l+1]...a[r]+=d,a[r+1]-=(r-l)*d+k
查询输出a[1]+a[2]...a[p],然后用线段树维护一下,这个题就做完了。(敲得也是十分顺利,写完直接过编译还输出了正确答案)(不开longlong见祖宗)

代码:

#include 
#include 
#include 
#include 
#define ls(x) x<<1
#define rs(x) x<<1|1
const int N=1e5+5;
using namespace std;
int n,m,a[N];
namespace segment
{
	struct smt
	{
		int l,r;
		long long sum,tag;
		smt(int ll,int rr,long long ss,long long tt)
		{
			l=ll;r=rr;sum=ss;tag=tt;
		}
		smt(){
		}
	}e[N<<2];
	void update(int x)
	{
		e[x].sum=e[ls(x)].sum+e[rs(x)].sum;
	}
	void pushup(int x,int v)
	{
		e[x].sum+=(e[x].r-e[x].l+1)*v;
		e[x].tag+=v;
	}
	void down(int x)
	{
		if(e[x].tag!=0)
		{
			pushup(ls(x),e[x].tag);
			pushup(rs(x),e[x].tag);
			e[x].tag=0;
		}
	}
	void build(int x,int l,int r)
	{
		e[x].l=l,e[x].r=r;
		if(l==r)
		{
			e[x].sum=a[r]-a[r-1];
			e[x].tag=0;
			return ;
		}
		int mid=(l+r)>>1;
		build(ls(x),l,mid);
		build(rs(x),mid+1,r);
		update(x);
	}
	void modify(int x,int l,int r,int v)
	{
		if(l<=e[x].l && e[x].r<=r)
		{
			e[x].sum+=(e[x].r-e[x].l+1)*v;
			e[x].tag+=v;
			return ;
		}
		down(x);
		int mid=(e[x].l+e[x].r)>>1;
		if(l<=mid)
		    modify(ls(x),l,r,v);
		if(r>mid)
		    modify(rs(x),l,r,v);
		update(x);
	}
	long long query(int x,int l,int r)
	{
		if(l<=e[x].l && e[x].r<=r)
		    return e[x].sum;
		down(x);
		int mid=(e[x].l+e[x].r)>>1;
		long long ret=0;
		if(l<=mid)
		    ret+=query(ls(x),l,r);
		if(r>mid)
		    ret+=query(rs(x),l,r);
		return ret;
	}
}
using namespace segment;
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	    scanf("%d",&a[i]);
	build(1,1,n);
	while(m--)
	{
		int opt,l,r,d,k;
		scanf("%d",&opt);
		if(opt==1)
		{
			scanf("%d %d %d %d",&l,&r,&k,&d);
			modify(1,l,l,k);
			if(l