考虑最优的决策,有一种是一直往右走,不在一个点上等,为什么是对的呢?
证明:如果在一个点上等一刻,不如把起点往前移一位。
破环为链复制一遍以方便记答案。
首先需要的时间一定(ge n-1),不妨枚举倒数第(n)个点是(i),再考虑走到(i)的时间最小是(t)才能在剩下(n-1)步标记所有点。
写成式子就是(forall jin[i,i+n-1] t+i-j>=t[j])
(t=max(t[j]+j-i)(jin[i,i+n-1]))
不难发现(jin [i,i+n-1])的限制可以改为(jin [i,2n]),因为(t[j+n]-(j+n)< t[j]-j)。
写成总式子:
(Ans=n+1+min_{i=1}^n i+max_{j=1}^{2n}t[j]-j)
把(t[j]-j)看成整体,相当于顺着做一个递减的单调栈,顺便统计一下答案。
用《楼房重建》那种线段树维护即可。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("
")
using namespace std;
const int N = 2e5 + 5;
#define i0 i + i
#define i1 i + i + 1
int n, m, tp;
int a[N], x, y;
int t[N * 4], fx[N * 4];
int query(int i, int x, int y, int p) {
if(x == y) {
return x <= n ? max(t[i], p) + x : 1e9;
}
int m = x + y >> 1;
if(p > t[i1]) {
int v = (m + 1 <= n) ? m + 1 + p : 1e9;
return min(v, query(i0, x, m, p));
} else {
return min(fx[i], query(i1, m + 1, y, p));
}
}
int pl, pr, px;
void add(int i, int x, int y) {
if(y < pl || x > pr) return;
if(x == y) {
t[i] = px; return;
}
int m = x + y >> 1;
add(i0, x, m); add(i1, m + 1, y);
t[i] = max(t[i0], t[i1]);
fx[i] = query(i0, x, m, t[i1]);
}
void xiu(int x) {
pl = pr = x, px = a[x] - x;
add(1, 1, 2 * n);
pl = pr = x + n, px = a[x] - (x + n);
add(1, 1, 2 * n);
}
int main() {
scanf("%d %d %d", &n, &m, &tp);
fo(i, 1, n) {
scanf("%d", &a[i]);
xiu(i);
}
int ans = query(1, 1, 2 * n, -1e9) + n - 1;
pp("%d
", ans);
fo(ii, 1, m) {
scanf("%d %d", &x, &y);
if(tp) x ^= ans, y ^= ans;
a[x] = y;
xiu(x);
ans = query(1, 1, 2 * n, -1e9) + n - 1;
pp("%d
", ans);
}
}