思路:
将公式y*(i-L)+x拆开:
i*y + (x-y*L)所以这样只有i*L是不确定的。由于y的范围是-5~5,y+5的范围就是0~10,这11个数,
所以可以根据y的数量建立多个线段树,用二维数组比较方便。
每次更新第y+5个线段树的L~R区间,更新这个点的最小值x-y*L。
查询时,只要比较ai与y在0~10的范围内的在这个点的最小值就行了(因为比较的是最小值,所以即使y位置未被更新也不会对结果产生影响。)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e9+10;
int tree[12][maxn<<2],lazy[12][maxn<<2],a[maxn],n,q;
void Init(){
for(int i=0;i<12;i++){
for(int j=0;j<(maxn<<2);j++){
tree[i][j] = INF;lazy[i][j] = INF;
}
}
}
int MIN(int x,int y){
return x<y?x:y;
}
void Update(int L,int R,int x,int ta[],int lz[],int rt,int l,int r){
if(L<=l&&r<=R){
ta[rt] = MIN(ta[rt],x);
lz[rt] = MIN(lz[rt],x);
return ;
}
int mid = (l+r)>>1;
if(lz[rt]!=INF){
lz[rt<<1] = MIN(lz[rt<<1],lz[rt]);
lz[rt<<1|1] = MIN(lz[rt<<1|1],lz[rt]);
ta[rt<<1] = MIN(ta[rt<<1],lz[rt]);
ta[rt<<1|1] = MIN(ta[rt<<1|1],lz[rt]);
lz[rt] = INF;
}
if(L<=mid) Update(L,R,x,ta,lz,rt<<1,l,mid);
if(R>mid) Update(L,R,x,ta,lz,rt<<1|1,mid+1,r);
ta[rt] = MIN(ta[rt<<1],ta[rt<<1|1]);
}
int Query(int pos,int ta[],int lz[],int rt,int l,int r){
if(l==r){
return ta[rt];
}
int mid = (l+r)>>1;
if(lz[rt]!=INF){
lz[rt<<1] = MIN(lz[rt<<1],lz[rt]);
lz[rt<<1|1] = MIN(lz[rt<<1|1],lz[rt]);
ta[rt<<1] = MIN(ta[rt<<1],lz[rt]);
ta[rt<<1|1] = MIN(ta[rt<<1|1],lz[rt]);
lz[rt] = INF;
}
if(pos<=mid) return Query(pos,ta,lz,rt<<1,l,mid);
else return Query(pos,ta,lz,rt<<1|1,mid+1,r);
}
int main(void){
Init();scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
while(q--){
int op;scanf("%d",&op);
if(op==2){
int x;scanf("%d",&x);
for(int i=0;i<=10;i++){
a[x] = MIN(a[x],(i-5)*x+Query(x,tree[i],lazy[i],1,1,n));
}
printf("%d\n",a[x]);
}else{
int l,r,x,y;scanf("%d%d%d%d",&l,&r,&x,&y);
Update(l,r,x-l*y,tree[y+5],lazy[y+5],1,1,n);
}
}
return 0;
}