• 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;
    }
    
    转载需注明出处。
  • 相关阅读:
    spring简介
    Thinkphp5 的sesssion在同一个控制器不同的方法无法获取session的原因和对策
    PHP单例模式--典型的三私一公
    10+ 值得收藏的开源后台模板
    PHP中&&与and、||与or的区别
    iview weapp输入组件input事件顺序
    php 获取post方法payload(json)形式参数的方法
    Git pull(拉取),push(上传)命令整理(详细)
    小程序 子组件传值
    php display_errors
  • 原文地址:https://www.cnblogs.com/jz929/p/11305640.html
Copyright © 2020-2023  润新知