A 题解 洛谷P1438

全程独立思考的情况下过的第一道蓝,肥肠激动,写个题解?

题目要实现的功能,在题目描述里写得很清楚

  1. 给要维护的序列的一部分加上一个等差数列 (区间修改)
  2. 查询这个序列某个位置的值 (单点查询)

作者只会打线段树1,完全不会这么复杂的区间修改,怎么办?

大概的思路就是给他降维打击,把复杂的区间修改变成简单的区间修改,同时也不能让查询变得太麻烦了。

自然而然地,我们就想到差分,先随便造一组数看看差分以后是啥情况。

原序列为 \(A=\{1,4,2,8,5,7\}\),差分序列为 \(D=\{1,3,-2,6,-3,2\}\)。

记等差数列为 \(S\),其中:

\[\begin{align*} S_1&=k,\\ S_2&=k+d,\\ &\cdots\\ S_n&=k+(n-1)d \end{align*} \]

将 \(A_2 \sim A_5\) 加上 \(S_1 \sim S_4\)

得到:

\[\begin{align*} A’&=\{1,4+k,2+k+d,8+k+2d,5+k+3d,7\} \\ D&=\{1,3+k,-2+d,6+d,-3+d,7-k-3d\} \end{align*} \]

对上式推广可以发现,在原序列 \(A\) 加上一个等差数列可以转化为对差分序列 \(D\) 进行一系列操作:

\[\begin{align*} D_l&= D_l +k\ ;\\ D_i&=D_i+d\ ; \quad(i\in[l+1,r])\\ D_{r+1}&=D_{r+1}-k-(r-l)d \ . \end{align*} \]

我们还知道:

\[\begin{align*} \because D_i &= A_i -A_{i-1} \\ \therefore \sum_{i=1}^{n}D_i & =(A_1-0)+(A_2-A_1)+\cdots+(A_n-A_{n-1})\\ &=A_n-0\\ &=A_n \end{align*} \]

所以只需要通过线段树求出 \(\sum \limits_{i=1}^{n}D_i\)就可以应付单点查询。

以下是代码,欢迎各位dl指正

点击查看代码
#include <bits/stdc++.h>
#define N signed(1e5+2)
#define cycle(i,a,b) for(int i=a;i<=b;i++)
#define mid (l+r>>1)
#define cnt (r-l+1)
#define int long long
using namespace std;
struct node{
	int val=0;
	int lazy=0;
	node* ls=nullptr;
	node* rs=nullptr;
	void pushup(){
		val=ls->val+rs->val;
	}
	void dn(int l,int r,int k){
		lazy+=k;
		val+=cnt*k;
	}
	void pushdn(int l,int r){
		ls->dn(l,mid,lazy);
		rs->dn(mid+1,r,lazy);
		lazy=0;
	}
};

int a[N],diff[N];
int n,m,x,y,k,d,ord,p,L,R,val;
node* root;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
node* build(int l,int r){
	node* pos=new node;
	if(l==r) pos->val=diff[l];
	else{
		pos->ls=build(l,mid);
		pos->rs=build(mid+1,r);
		pos->pushup();
	}
	return pos;
}
void update(int l,int r,node* now){
	if(L>R) return;
	if(r<L||R<l)return;
	if(L<=l&&r<=R) now->dn(l,r,val);
	else{
		now->pushdn(l,r);
		if(L<=mid) update(l,mid,now->ls);
		if(R>mid) update(mid+1,r,now->rs);
		now->pushup();
	}
}
int query(int l,int r,node* now){
	if(R<l||r<L) return 0;
	if(L<=l&&r<=R) return now->val;
	else{
		now->pushdn(l,r);
		int ql=query(l,mid,now->ls);
		int qr=query(mid+1,r,now->rs);
		now->pushup();
		return ql+qr;
	}
}
signed main(){
	n=read(),m=read();
	cycle(i,1,n){
		cin>>a[i];
		diff[i]=a[i]-a[i-1];
	}
	root=build(1,n);
	cycle(i,1,m){
		ord=read();
		if(ord==1){
			x=read(),y=read(),k=read(),d=read();
			L=x,R=x,val=k;
			update(1,n,root);
			L=x+1,R=y,val=d;
			update(1,n,root);
			L=y+1,R=y+1,val=-k-(y-x)*d;
			update(1,n,root);
		}else{
			p=read();
			L=1,R=p;
			cout<<query(1,n,root)<<endl;
		}
	}
	return 0;
}
有问题的话请各位dl在评论区对线,非常感谢!
上一篇:tomcat设置定时重启


下一篇:CSS 使用 sroll-snap-type 优化滚动