因为本题只存在单点查询,所以我们考虑每次不更新到叶子节点,而是直接更新到当前区间,如果同一区间存在多次更新,我们每次只需要保留最优情况,每次查询,我们途中一定会经过这些区间,向上回溯的时候取最小值即可.
线段树维护两个值,一个是区间[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;
} 
京公网安备 11010502036488号