题解 P1438 【无聊的数列】
Solution
- 感觉并不需要差分诶!
- 而且没有区间查询诶!
发现数列一开始的的值根本不用管诶, 所以我们维护的不过就是这个数列的部分所具有的等差的性质而已.
所以标记根本不用下放, 也就是标记永久化.我们看标记维护的是啥, 首先标记维护这个区间被加上的等差数列的性质, 因为等差数列具有可加性.所以在一个等差数列上加上一个等差数列仍然是一个等差数列, 因此标记可以这样写:
struct Flag{
int l,r,k,d;
Flag(){l=r=k=d=0;}
Flag(int a,int b,int c,int e){l=a,r=b,k=c,d=e;}
int val(int p){
if(p>r||p<l)return false;
return k+(p-l)*d;
}
int update(int L,int R,Flag o){
k+=(L-o.l)*o.d+o.k,d+=o.d,l=L,r=R;
}
};
- val 表示这个数列中某一个位置的值.
- update 表示在这个等差数列上加上一个等差数列.
如何查询某个位置的值呢?用数列原本这个位置的值加上等差数列的值.也就是在线段树中查找
Code
指针线段树
#include<cstdio>
#define N 100005
using namespace std;
struct Flag{
int l,r,k,d;
Flag(){l=r=k=d=0;}
Flag(int a,int b,int c,int e){l=a,r=b,k=c,d=e;}
int val(int p){
if(p>r||p<l)return false;
return k+(p-l)*d;
}
int update(int L,int R,Flag o){
k+=(L-o.l)*o.d+o.k,d+=o.d,l=L,r=R;
}
};
struct Node{
Flag f;
Node *ls,*rs;
Node(){}
}pool[N<<1];
Node* new_Node(){
static int cnt=0;
return &pool[cnt++];
}
void build(int l,int r,Node *now){
if(l==r)return ;
int mid=(l+r)>>1;
now->ls=new_Node(),now->rs=new_Node();
build(l,mid,now->ls);
build(mid+1,r,now->rs);
}
void Modify(int l,int r,Flag o,Node* now){
if(l>=o.l&&r<=o.r){now->f.update(l,r,o);return ;}
int mid=(l+r)>>1;
if(o.l<=mid)Modify(l,mid,o,now->ls);
if(o.r>mid)Modify(mid+1,r,o,now->rs);
}
int query(int l,int r,int p,Node* now){
int ans=now->f.val(p);
if(l==r)return ans;
int mid=(l+r)>>1;
if(p<=mid)return ans+query(l,mid,p,now->ls);
else return ans+query(mid+1,r,p,now->rs);
}
int s[N];
int main(){
int n,m;Node *root=new_Node();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&s[i]);
build(1,n,root);
int a,b,c,d,e;
while(m--){
scanf("%d",&a);
if(a==1){
scanf("%d%d%d%d",&b,&c,&d,&e);
Modify(1,n,(Flag){b,c,d,e},root);
}
else {
scanf("%d",&b);
printf("%d",s[b]+query(1,n,b,root));
}
}
return 0;
}