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\n", 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;
}