jzoj 6278. 2019.8.5【NOIP提高组A】跳房子

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;
}
上一篇:vue 实现导航锚点联动


下一篇:jump-game