转盘
题目背景:
分析:线段树
又是神题一道,考场上连暴力都不会打,完全下不了手。
首先有一个非常显然的结论,对于每个询问,一定有一种最优解是从某个点开始先等待一段时间,然后直接走完一圈,考虑一个大致的证明,如果我们在不是起始点的其他点停顿的话,在相同时间的情况下,会导致除了这个点和这个点之后的其他所有点的最后一个位置提前(显然只有最后一次出现的位置有用),所以肯定不优,那么我们就证明了这个结论。
为了方面后面的推导,我们考虑把序列倍长,那么我们需要求的就
这样就可以直接用线段树维护出答案,每一次直接取根的val即可。具体细节详见代码,时间复杂度O(nlog2n)。
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
inline char read() {
static const int IN_LEN = 1024 * 1024;
static char buf[IN_LEN], *s, *t;
if (s == t) {
t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
if (s == t) return -1;
}
return *s++;
}
///*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return ;
if (c == '-') iosig = true;
}
for (x = 0; isdigit(c); c = read())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
*oh++ = c;
}
template<class T>
inline void W(T x) {
static int buf[30], cnt;
if (x == 0) write_char('0');
else {
if (x < 0) write_char('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) write_char(buf[cnt--]);
}
}
inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
/*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
if (c == '-') iosig = true;
for (x = 0; isdigit(c); c = getchar())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int MAXN = 200000 + 10;
int n, x, y, m, p;
int a[MAXN];
struct node {
int val, max;
} tree[MAXN << 2 | 1];
inline int query(int k, int l, int r, int val) {
if (l == r) return std::max(tree[k].max, val) + l;
int mid = l + r >> 1;
if (val <= tree[k << 1 | 1].max)
return std::min(tree[k].val, query(k << 1 | 1, mid + 1, r, val));
else return std::min(query(k << 1, l, mid, val), mid + 1 + val);
}
inline void update(int k, int l, int mid) {
tree[k].val = query(k << 1, l, mid, tree[k << 1 | 1].max);
tree[k].max = std::max(tree[k << 1].max, tree[k << 1 | 1].max);
}
inline void build(int k, int l, int r) {
if (l == r) {
int cur = (l > n) ? (a[l - n] - l) : (a[l] - l);
tree[k].max = cur, tree[k].val = cur + l;
return ;
}
int mid = l + r >> 1;
build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r);
update(k, l, mid);
}
inline void modify(int k, int l, int r, int pos, int x) {
if (l == r) {
tree[k].max = x, tree[k].val = x + l;
return ;
}
int mid = l + r >> 1;
if (pos <= mid) modify(k << 1, l, mid, pos, x);
else modify(k << 1 | 1, mid + 1, r, pos, x);
update(k, l, mid);
}
inline void solve() {
int last;
R(n), R(m), R(p);
for (int i = 1; i <= n; ++i) R(a[i]);
build(1, 1, 2 * n), W((last = tree[1].val + n - 1)), write_char('\n');
while (m--) {
R(x), R(y);
if (p) x ^= last, y ^= last;
modify(1, 1, 2 * n, x, y - x), modify(1, 1, 2 * n, x + n, y - x - n);
W((last = tree[1].val + n - 1)), write_char('\n');
}
}
int main() {
//freopen("in.in", "r", stdin);
solve();
flush();
return 0;
}