nblogs-markdown">
Description
详见OJ
Solution
看完题后第一反应是倍增。
由于有修改操作,就尝试着打了个和昨天一样,(但是是假的)启发式倍增。
结果被出题人无意中狂怼,(MLE0)(超了一点点),减小空间后(TLE25)。。。
(其中一个)正解是线段树。
我们对于一个区间([l,r])(线段树内编号为(x)),维护一个(t[x].tov[]),(t[x].tov[i])表示从第(l)列的第(i)行会走到第(r + 1)列的第几行。
可以先预处理一遍,求出所有的(t[x].tov[i])。
设当前的位置为((now[0],now[1]))
对于查询操作:
我们可以尝试着分块。
对于步数(k),如果小于等于(m - now[1] +1)的,就直接用线段树跳。
否则的话,我们就先走到第一列。
因为线段树我们的(t[1].tov[i])就表示第(1)列第(i)行第一列走一波可以走回第(1)列的第几行。
所以我们可以(m)步(m)步地走,并每次标记一下,找到循环节。
我们就可以将(k)模循环节了。循环节最大为(n *m)。
这样我们再(m)步(m)步地走,就可以在至多(n)次走完,多余的用线段树跳即可。
对于修改操作:
我们只需对于第(b - 1)列的进行线段树修改即可。
因为只有这一列会更改跳到的位置。
回溯的时候也会被相应的更改到。
Code
#include <cstdio> #include <cstring> #define N 2010 #define mem(x, a) memset(x, a, sizeof x) #define fo(x, a, b) for (register int x = a; x <= b; x++) using namespace std; struct node{int tov[N];}t[N << 5]; int n, m, a[N][N], bz[N], q, now[2], jie, rd; bool check = 1; char s[7]; inline int read() { int x = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return x; } inline int mx(int x, int y, int z, int j) { if (a[x][j] > a[y][j] && a[x][j] > a[z][j]) return x; if (a[y][j] > a[z][j]) return y; return z; } void ycl(int x, int l, int r) { if (l == r) { int tt = (l == m) ? 1 : l + 1; fo(i, 1, n) t[x].tov[i] = mx(i, (i == 1) ? n : i - 1, (i == n) ? 1 : i + 1, tt); return; } int mid = l + r >> 1; ycl(x << 1, l, mid), ycl(x << 1 | 1, mid + 1, r); fo(i, 1, n) t[x].tov[i] = t[x << 1 | 1].tov[t[x << 1].tov[i]]; } void jump(int x, int l, int r, int fl, int fr) { if (fl <= l && fr >= r) {now[0] = t[x].tov[now[0]]; now[1] = (r == m) ? 1 : r + 1; return;} int mid = l + r >> 1; if (fl <= mid) jump(x << 1, l, mid, fl, fr); if (fr > mid) jump(x << 1 | 1, mid + 1, r, fl, fr); } void change(int x, int l, int r, int f) { if (l == r) { int tt = (l == m) ? 1 : l + 1; fo(i, 1, n) t[x].tov[i] = mx(i, (i == 1) ? n : i - 1, (i == n) ? 1 : i + 1, tt); return; } int mid = l + r >> 1; if (f <= mid) change(x << 1, l, mid , f); else change(x << 1 | 1, mid + 1, r, f); fo(i, 1, n) t[x].tov[i] = t[x << 1 | 1].tov[t[x << 1].tov[i]]; } int main() { freopen("jump.in", "r", stdin); freopen("jump.out", "w", stdout); n = read(), m = read(); fo(i, 1, n) fo(j, 1, m) a[i][j] = read(); ycl(1, 1, m); q = read(); now[0] = now[1] = 1; while (q--) { scanf("%s", s + 1); if (s[1] == 'm') { rd = read(); if (now[1] + rd - 1 <= m) jump(1, 1, m, now[1], now[1] + rd - 1); else { if (now[1] != 1) { rd -= m - now[1] + 1; jump(1, 1, m, now[1], m); } if (! check) rd %= jie; else { mem(bz, 0); bz[now[0]] = 1; jie = 1; while (rd >= m) { rd -= m, jump(1, 1, m, 1, m); if (bz[now[0]]) break; jie += m, bz[now[0]] = jie; } if (rd >= m) check = 0, jie = jie - bz[now[0]] + m, rd %= jie; } while (rd >= m) rd -= m, jump(1, 1, m, 1, m); if (rd > 0) { if (now[1] + rd - 1 > m) { rd -= m - now[1] + 1; jump(1, 1, m, now[1], m); jump(1, 1, m, 1, rd); } else jump(1, 1, m, now[1], now[1] + rd - 1); } } printf("%d %d ", now[0], now[1]); } else { rd = read(); int y = read(); a[rd][y] = read(); change(1, 1, m, (y == 1) ? m : y - 1); check = 1; } } return 0; }