zoukankan      html  css  js  c++  java
  • 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
    ", 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;
    }
    转载需注明出处。
  • 相关阅读:
    Mysql:mysqlslap:基于5.7.36的修改版:不自动创建测试schma、不删除测试schema、默认生成初始化记录数为1
    Mysql:mysqlslap:自带的简单压力测试工具:使用、bug等:续(为了方便阅读)
    《微服务设计》
    E: Unable to locate package vim
    'dependencies.dependency.version' for org.testng:testng:jar is either LATEST or RELEASE (both of them are being deprecated)
    Linux
    硬盘IO性能估算入门
    [转载]在 Linux 中使用 fsck 命令修复文件系统
    阿里巴巴 P8、P9 及以上到底是什么水平?
    课程表-python
  • 原文地址:https://www.cnblogs.com/jz929/p/11817487.html
Copyright © 2011-2022 走看看