题意
给一个长度为
n
n
n的序列
A
1
,
A
2
,
…
A
n
A_1,A_2,\dots A_n
A1,A2,…An,你需要支持以下两种操作:
操作1:L R X Y,对所有的
L
≤
n
≤
R
L \leq n \leq R
L≤n≤R赋值
A
i
=
m
i
n
(
A
i
,
(
i
−
L
)
∗
Y
+
X
)
A_i = min(A_i, (i - L) * Y + X)
Ai=min(Ai,(i−L)∗Y+X)。其中L,R,X,Y均为整数,且有
1
≤
L
≤
R
≤
n
1\leq L \leq R\leq n
1≤L≤R≤n,
∣
X
∣
≤
100000
\left| X\right|\leq 100000
∣X∣≤100000,
∣
Y
∣
≤
5
\left| Y\right|\le 5
∣Y∣≤5。
操作 2:
x
x
x,询问
A
x
A_x
Ax 的值,这里
x
x
x 是整数,且有
1
≤
x
≤
n
1\le x\le n
1≤x≤n。
数据范围
1
≤
n
,
q
≤
1
0
5
1 \leq n,q \leq 10^5
1≤n,q≤105
−
1
0
5
≤
A
i
≤
1
0
5
-10^5 \leq A_i \leq 10^5
−105≤Ai≤105
思路
首先观察
A
i
A_i
Ai的表达式
(
i
−
L
)
∗
Y
+
X
(i - L) * Y + X
(i−L)∗Y+X,我们可以对其进行化简,即:
i
∗
Y
+
(
X
−
L
∗
Y
)
i * Y + (X - L * Y)
i∗Y+(X−L∗Y)。
我们观察到
Y
Y
Y的取值范围特别小,于是我们就可以开
11
11
11个线段树去维护,每一个线段树代表一个
Y
Y
Y,这样表达式中的
Y
Y
Y就固定了。因为
i
∗
Y
i*Y
i∗Y是定值,因此我们可以放到最后直接加上,那么原问题就等价于处理
X
−
L
∗
Y
X - L * Y
X−L∗Y了。这显然是一个区间修改,维护最小值问题。
在线段树中,维护两个量
m
i
n
,
l
a
z
y
min,lazy
min,lazy,这里的
l
a
z
y
lazy
lazy指的是修改后的最小值标记。
在查找答案的过程中,遍历每一个线段树,找到其中的最小值再加上
i
∗
Y
i*Y
i∗Y,最后再与
A
i
A_i
Ai找一个最小值,就是最终的答案了。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010, inf = 0x3f3f3f3f;
int n, q;
int w[N];
struct Node
{
int l, r, min1, lazy;
}tr[N * 4][11];
void pushup(int k,int u)
{
tr[u][k].min1 = min(tr[u<<1][k].min1, tr[u<<1|1][k].min1);
}
void pushdown(int k,int u)
{
auto &root = tr[u][k], &left = tr[u<<1][k], &right = tr[u<<1|1][k];
if(root.lazy!=inf){
int tmp = root.lazy;
left.lazy = min(left.lazy, tmp), left.min1 = min(left.min1, tmp);
right.lazy = min(right.lazy, tmp), right.min1 = min(right.min1, tmp);
root.lazy = inf;
}
}
void build(int k,int u,int l,int r)
{
tr[u][k] = {l,r,inf,inf};
if(l==r) return;
else{
int mid = l + r >> 1;
build(k,u<<1,l,mid), build(k,u<<1|1,mid+1,r);
pushup(k,u);
}
}
void modify(int k,int u,int l,int r,int x)
{
if(tr[u][k].l>=l&&tr[u][k].r<=r){
tr[u][k].lazy = min(tr[u][k].lazy, x);
tr[u][k].min1 = min(tr[u][k].min1, x);
}
else{
pushdown(k,u);
int mid = tr[u][k].l + tr[u][k].r >> 1;
if(l<=mid) modify(k,u<<1,l,r,x);
if(r>mid) modify(k,u<<1|1,l,r,x);
pushup(k,u);
}
}
int query(int k,int u,int x)
{
if(tr[u][k].l==tr[u][k].r) return tr[u][k].min1;
pushdown(k,u);
int mid = tr[u][k].l + tr[u][k].r >> 1;
if(x<=mid) return query(k,u<<1,x);
else return query(k,u<<1|1,x);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=0;i<11;i++) build(i,1,1,n);
while(q--){
int op;
scanf("%d",&op);
if(op == 1){
int l, r, x, y;
scanf("%d%d%d%d",&l,&r,&x,&y);
modify(y+5,1,l,r,x-l*y);
}
else{
int x;
scanf("%d",&x);
int ans = w[x];
for(int i=0;i<11;i++) ans = min(ans, x*(i-5)+query(i,1,x));
printf("%d\n",ans);
}
}
return 0;
}