全程独立思考的情况下过的第一道蓝,肥肠激动,写个题解?
题目要实现的功能,在题目描述里写得很清楚
- 给要维护的序列的一部分加上一个等差数列 (区间修改)
- 查询这个序列某个位置的值 (单点查询)
作者只会打线段树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;
}