因为本题只存在单点查询,所以我们考虑每次不更新到叶子节点,而是直接更新到当前区间,如果同一区间存在多次更新,我们每次只需要保留最优情况,每次查询,我们途中一定会经过这些区间,向上回溯的时候取最小值即可.
            线段树维护两个值,一个是区间[l,r]上,L的值,另一个是这个区间的差值(可以想象成一个等差数列或者线段).
            不是很懂的可以了解一下扫描线的思想,同样也是不更新到叶子节点si

Ac_Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <bitset>
#include <vector>
#include <map>
#include <string>
#include <cstring>
#define fir first
#define sec second
using namespace std;

const int maxn = 1e5+7;
const int INF = 1e9+7;

int n,m;
int a[maxn];
int d[maxn<<2],f[maxn<<2];

void build(int l,int r,int num) {
    d[num] = 0;
    f[num] = INF;
    if(l==r) {
        f[num] = a[l];
        d[num] = 0;
        return ;
    }
    int mid = (l+r) >>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
    return ;
}

void modify(int l,int r,int num,int le,int ri,int x,int y) {
    if(le<=l && r<=ri) {
        if(f[num] <=  (l-le) * y+x && (r-le) * y+x >= f[num] + (r-l) * d[num]) return ;
        if(f[num] >= (l-le) * y+x && ((r-le) * y+x <= f[num] + (r-l) * d[num])) {
            f[num] = (l-le) *y +x;
            d[num] = y;
            return ;
        }
    }
    int mid = (l+r) >>1;
    if(le<=mid) modify(l,mid,num<<1,le,ri,x,y);
    if(mid< ri) modify(mid+1,r,num<<1|1,le,ri,x,y);
}

int quriy(int l,int r,int num,int pos) {
    if(l==r) return f[num];
    int mid = (l+r) >>1;
    if(pos <= mid) return min(f[num] + (pos-l)*d[num] ,quriy(l,mid,num<<1,pos));
    else return min(f[num] + (pos -l) * d[num],quriy(mid+1,r,num<<1|1,pos));
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
    }
    build(1,n,1);
    while(m--) {
        int op,l,r,x,y;
        scanf("%d",&op);
        if(op == 1) {
            scanf("%d%d%d%d",&l,&r,&x,&y);
            modify(1,n,1,l,r,x,y);
        }
        else {
            scanf("%d",&x);
            printf("%d\n",quriy(1,n,1,x));
        }
    }
    return 0;
}