如果一种最优解是:在时刻
t
t
t从位置
x
x
x开始,从时刻
t
+
1
t+1
t+1开始共有
t
1
t1
t1个时刻选择当前物品,有
t
2
t2
t2个时刻选择下一个物品,那么这和在时刻
t
+
t
1
t+t1
t+t1从位置
x
x
x开始,从时刻
t
+
1
t+1
t+1开始都不选择当前物品,实际上是等价的
那么只要考虑不停留的情况,问题转化为选择一个最小的开始时间
b
x
(
t
≥
0
)
b_{x}(t≥0)
bx(t≥0),使得从位置
x
x
x开始,花
n
n
n个时刻完成标记,答案即
t
+
n
−
1
t+n-1
t+n−1
首先,为了处理环的情况,令
T
T
T数组倍长,即
T
i
=
T
i
−
n
(
n
+
1
≤
i
≤
2
n
)
T_{i}=T_{i-n}(n+1≤i≤2n)
Ti=Ti−n(n+1≤i≤2n)
因为要求满足
t
+
i
−
x
≥
T
i
(
∀
i
,
x
≤
i
≤
x
+
n
−
1
)
t+i-x≥T_{i}(\forall i,x≤i≤x+n-1)
t+i−x≥Ti(∀i,x≤i≤x+n−1)
所以
b
x
bx
bx即
m
a
x
i
=
x
x
+
n
−
1
T
i
−
i
max_{i=x}^{x+n-1}T_{i}-i
maxi=xx+n−1Ti−i
那么令
a
i
=
T
i
−
i
a_{i}=T_{i}-i
ai=Ti−i
发现
T
i
=
T
i
−
n
(
x
+
n
≤
i
≤
2
n
)
T_{i}=T_{i-n}(x+n≤i≤2n)
Ti=Ti−n(x+n≤i≤2n)
说明
a
i
<
a
i
−
n
(
x
+
n
≤
i
≤
2
n
)
a_{i}<a_{i-n}(x+n≤i≤2n)
ai<ai−n(x+n≤i≤2n)
那么
b
x
b_{x}
bx可以改写为后缀最大值的形式:
m
a
x
i
=
x
2
n
a
i
(
1
≤
x
≤
n
)
max_{i=x}^{2n}a_{i}(1≤x≤n)
maxi=x2nai(1≤x≤n)
因为
a
n
s
=
m
i
n
(
b
x
+
x
)
ans=min(b_{x}+x)
ans=min(bx+x)
所以如果对于
l
≤
i
≤
r
l≤i≤r
l≤i≤r满足
b
i
b_{i}
bi全部相同,那么选
l
l
l一定比选
[
l
+
1
,
r
]
[l+1,r]
[l+1,r]中的任何一个要优
将所有这样区间
[
l
,
r
]
[l,r]
[l,r]中的
l
l
l取出,就形成了一个关于
a
i
a_{i}
ai的单调下降子序列
特别地,这个子序列的每一项
d
i
d_{i}
di都要满足
a
j
<
a
i
(
∀
j
,
i
<
j
≤
2
n
)
a_{j}<a_{i}(\forall j,i<j≤2n)
aj<ai(∀j,i<j≤2n)
其实只要最后一项满足上述条件即可,也就是对这个单调下降子序列的末项作了限制
那么为了方便,从右到左维护一个单调上升子序列,也就是取出所有的
r
r
r放入
c
c
c数组,所有的
c
i
+
1
c_{i}+1
ci+1就是要选的
l
l
l,对答案的贡献即
(
1
)
.
m
i
n
(
a
c
i
+
1
+
c
i
+
1
)
(
1
≤
i
<
m
)
(1).min(a_{c_{i+1}}+c_{i}+1)(1≤i<m)
(1).min(aci+1+ci+1)(1≤i<m)
特别地,由于
x
x
x和
c
c
c的取值在
[
1
,
n
]
[1,n]
[1,n],所以当
c
m
!
=
n
c_{m}!=n
cm!=n时,位置
c
m
+
1
c_{m}+1
cm+1对答案的贡献是
(
2
)
.
m
a
x
i
=
n
+
1
2
n
a
i
(2).max_{i=n+1}^{2n}a_{i}
(2).maxi=n+12nai
即
m
a
x
i
=
1
n
a
i
−
n
max_{i=1}^{n}a_{i}-n
maxi=1nai−n
因为在此条件下,
c
m
+
1
,
n
,
n
+
1
c_{m}+1,n,n+1
cm+1,n,n+1必处于同一区间
[
l
,
r
]
[l,r]
[l,r]中
当
c
m
=
n
c_{m}=n
cm=n时
(
2
)
(2)
(2)显然成立
于是对
(
1
)
,
(
2
)
,
a
c
1
+
1
(1),(2),a_{c_{1}}+1
(1),(2),ac1+1取最小值即可
维护线段树,记
c
a
l
c
(
l
,
r
,
v
,
p
)
calc(l,r,v,p)
calc(l,r,v,p)为一个四元组,表示节点
p
p
p(对应区间
[
l
,
r
]
[l,r]
[l,r]),末项
>
v
>v
>v的单调上升子序列(从右到左)的信息:
(
c
1
,
c
m
,
a
c
1
,
m
i
n
(
a
c
i
+
1
+
c
i
+
1
)
(
1
≤
i
<
m
)
)
(c_{1},c_{m},a_{c_{1}},min(a_{c_{i+1}}+c_{i}+1)(1≤i<m))
(c1,cm,ac1,min(aci+1+ci+1)(1≤i<m))
记
v
a
l
[
p
]
val[p]
val[p]表示节点
p
p
p对应区间的
m
a
x
(
a
i
)
max(a_{i})
max(ai)
记
b
[
p
]
b[p]
b[p]表示
c
a
l
c
(
l
,
m
i
d
,
v
a
l
[
p
3
]
,
p
2
)
calc(l,mid,val[p3],p2)
calc(l,mid,val[p3],p2),
p
2
,
p
3
p2,p3
p2,p3为左右子节点
修改回溯时要更新
v
a
l
val
val和
b
b
b
下面讨论如何计算
c
a
l
c
(
l
,
r
,
v
,
p
)
calc(l,r,v,p)
calc(l,r,v,p)
若
v
a
l
[
p
3
]
≤
v
val[p3]≤v
val[p3]≤v,那么这个子序列与
p
3
p3
p3无关,递归
p
2
p2
p2即可
否则,
p
2
p2
p2对子序列的贡献依然是
b
[
p
]
b[p]
b[p]
显然回溯时
b
[
p
2
]
b[p2]
b[p2]会比
c
a
l
c
(
l
,
m
i
d
,
v
a
l
[
p
3
]
,
p
2
)
calc(l,mid,val[p3],p2)
calc(l,mid,val[p3],p2)先算
时间复杂度
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
Code
#include<bits/stdc++.h>usingnamespace std;#define p2 p << 1#define p3 p << 1 | 1template<classt>inlinevoidread(t & res){char ch;while(ch =getchar(),!isdigit(ch));
res = ch ^48;while(ch =getchar(),isdigit(ch))
res = res *10+(ch ^48);}constint e =1e5+5, inf =0x3f3f3f3f;struct node
{int c1, cm, a1, res;}b[e *4];int n, m, val[e *4], a[e], op, ans;inline node calc(int l,int r,int v,int p){if(l == r)return val[p]> v ?(node){l, r, val[p], inf}:(node){0, inf, inf, inf};int mid = l + r >>1;if(val[p3]<= v)returncalc(l, mid, v, p2);if(val[p2]<= val[p3])returncalc(mid +1, r, v, p3);
node lc = b[p], rc =calc(mid +1, r, v, p3);if(!lc.c1)return rc;return(node){lc.c1, rc.cm, lc.a1,min(min(lc.res, rc.res), rc.a1 + lc.cm +1)};}inlinevoidupdate(int l,int r,int s,int v,int p){if(l == r){
val[p]= v;return;}int mid = l + r >>1;if(s <= mid)update(l, mid, s, v, p2);elseupdate(mid +1, r, s, v, p3);
val[p]=max(val[p2], val[p3]);
b[p]=calc(l, mid, val[p3], p2);}inlinevoidbuild(int l,int r,int p){if(l == r){
val[p]= a[l]- l;return;}int mid = l + r >>1;build(l, mid, p2);build(mid +1, r, p3);
val[p]=max(val[p2], val[p3]);
b[p]=calc(l, mid, val[p3], p2);}intmain(){int i, x, y;read(n);read(m);read(op);for(i =1; i <= n; i++)read(a[i]);build(1, n,1);
node z =calc(1, n, val[1]- n,1);
ans =min(z.res,min(z.a1 +1, val[1]- n + z.cm +1));
ans += n -1;printf("%d\n", ans);while(m--){read(x);read(y);if(op){
x ^= ans;
y ^= ans;}
a[x]= y;update(1, n, x, y - x,1);
node z =calc(1, n, val[1]- n,1);
ans =min(z.res,min(z.a1 +1, val[1]- n + z.cm +1));
ans += n -1;printf("%d\n", ans);}return0;}