题目

题目大意

给你一个矩阵,从\((1,1)\)开始,每次往右上、右、右下三个格子中权值最大的那个跳。

第一行上面是第\(n\)行,第\(m\)列右边是第\(1\)列。反之同理。

有两个操作:跳\(K\)步和修改某行某列的权值。

\(n,m\leq 2000\)


思考历程

一开始觉得似乎可以倍增,但这个修改操作太烦人,想了很久感觉倍增不可做。

最终打暴力+判断循环节。然而爆\(10\)了。

后来发现少打了个\(+1\),加上之后,居然水了\(85\)分。


正解

设\(jump_i\)表示\(i\)行\(1\)列开始跳\(m\)步会到哪一行。

有了这个东西,询问就很好做了。先跳到\(1\)列,然后每次\(m\)步\(m\)步地跳,判一下循环节。

重点是这个东西怎么维护。

按照题解做法,在某个点修改之后往前搞。由于改变方向的点都是在一个区间之内的,所以维护左端点和右端点,一直做到\(1\)列即可。

然而……

无数人有实践表明,这样打不出啊!!!

细节太多了……

于是有个造福人类的线段树做法。

我们可以计算出\(i\)列到\(i+1\)列的映射,用个长度为\(n\)的数组存下来。

然后利用线段树合并,处理出\(1\)列到\(n+1\)列的映射,也就是\(jump\)数组。

查询的时候一模一样。至于修改,直接单点修改,单次修改复杂度\(O(n\lg m)\)

也就比题解做法多了一个\(lg\)而已,但代码可要方便很多。


代码

(线段树做法)

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 2010
inline int input(){
char ch=getchar();
while (ch<'0' || '9'<ch)
ch=getchar();
int x=0;
do{
x=x*10+ch-'0';
ch=getchar();
}
while ('0'<=ch && ch<='9');
return x;
}
int n,m;
int a[N][N];
int nowx=1,nowy=1;
inline int dn(int x){return x==n?1:x+1;}
inline int up(int x){return x==1?n:x-1;}
inline int ri(int x){return x==m?1:x+1;}
inline int le(int x){return x==1?m:x-1;}
inline int nxt(int x,int y){
y=ri(y);
int ux=up(x),dx=dn(x);
if (a[ux][y]>a[x][y])
x=ux;
if (a[dx][y]>a[x][y])
x=dx;
return x;
}
inline void get_next(int &x,int &y){
x=nxt(x,y);
y=ri(y);
}
int jump[N<<4][N];
int vis[N],BZ,tim[N];
void build(int k,int l,int r){
if (l==r){
for (int i=1;i<=n;++i)
jump[k][i]=nxt(i,l);
return;
}
int mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
for (int i=1;i<=n;++i)
jump[k][i]=jump[k<<1|1][jump[k<<1][i]];
}
void change(int k,int l,int r,int y){
if (l==r){
for (int i=1;i<=n;++i)
jump[k][i]=nxt(i,y);
return;
}
int mid=l+r>>1;
if (y<=mid)
change(k<<1,l,mid,y);
else
change(k<<1|1,mid+1,r,y);
for (int i=1;i<=n;++i)
jump[k][i]=jump[k<<1|1][jump[k<<1][i]];
}
int main(){
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
n=input(),m=input();
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
a[i][j]=input();
build(1,1,m);
int Q;
scanf("%d",&Q);
char op[7];
while (Q--){
scanf("%s",op);
if (*op=='m'){
int k=input(),i;
for (;k && nowy!=1;--k)
get_next(nowx,nowy);
if (k==0){
printf("%d %d\n",nowx,nowy);
continue;
}
vis[nowx]=++BZ;
tim[nowx]=i=0;
while (k>=m){
k-=m;
++i;
nowx=jump[1][nowx];
if (vis[nowx]!=BZ){
vis[nowx]=BZ;
tim[nowx]=i;
continue;
}
k%=m*(i-tim[nowx]);
break;
}
for (;k>=m;k-=m)
nowx=jump[1][nowx];
for (;k;--k)
get_next(nowx,nowy);
printf("%d %d\n",nowx,nowy);
}
else{
int x=input(),y=input(),c=input();
a[x][y]=c;
change(1,1,m,le(y));
}
}
return 0;
}

总结

好多时候都可以用到线段树呢……

[JZOJ6278] 2019.8.5【NOIP提高组A】跳房子的更多相关文章

  1. NOIP提高组2004 合并果子题解

    NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消 ...

  2. 计蒜客 NOIP 提高组模拟竞赛第一试 补记

    计蒜客 NOIP 提高组模拟竞赛第一试 补记 A. 广场车神 题目大意: 一个\(n\times m(n,m\le2000)\)的网格,初始时位于左下角的\((1,1)\)处,终点在右上角的\((n, ...

  3. 1043 方格取数 2000 noip 提高组

    1043 方格取数  2000 noip 提高组 题目描述 Description 设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样 ...

  4. [NOIP提高组2018]货币系统

    [TOC] 题目名称:货币系统 来源:2018年NOIP提高组 链接 博客链接 CSDN 洛谷博客 洛谷题解 题目链接 LibreOJ(2951) 洛谷(P5020) 大视野在线评测(1425) 题目 ...

  5. NOIP提高组初赛难题总结

    NOIP提高组初赛难题总结 注:笔者开始写本文章时noip初赛新题型还未公布,故会含有一些比较老的内容,敬请谅解. 约定: 若无特殊说明,本文中未知数均为整数 [表达式] 表示:在表达式成立时它的值为 ...

  6. 津津的储蓄计划 NOIp提高组2004

    这个题目当年困扰了我许久,现在来反思一下 本文为博客园ShyButHandsome的原创作品,转载请注明出处 右边有目录,方便快速浏览 题目描述 津津的零花钱一直都是自己管理.每个月的月初妈妈给津津\ ...

  7. 2018.12.30【NOIP提高组】模拟赛C组总结

    2018.12.30[NOIP提高组]模拟赛C组总结 今天成功回归开始做比赛 感觉十分良(zhōng)好(chà). 统计数字(count.pas/c/cpp) 字符串的展开(expand.pas/c ...

  8. 2018.12.08【NOIP提高组】模拟B组总结(未完成)

    2018.12.08[NOIP提高组]模拟B组总结 diyiti 保留道路 进化序列 B diyiti Description 给定n 根直的木棍,要从中选出6 根木棍,满足:能用这6 根木棍拼出一个 ...

  9. 2013 Noip提高组 Day2

    3288积木大赛 正文 题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前 ...

  10. 2013 Noip提高组 Day1

    3285 转圈游戏 2013年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description ...

随机推荐

  1. C#异步编程----async和await组合的写法

    微软示例: private async void StartButton_Click(object sender, RoutedEventArgs e) { // ExampleMethodAsync ...

  2. vs2013 命名空间“Microsoft.Office”中不存在类型或命名空间名称“Interop”。是否缺少程序集引用?

    参考博文: 解决办法:添加引用/com/Microsoft Office 11.0 Object Library 然后在程序中 C#代码 using Microsoft.Office.Interop. ...

  3. ubuntu配置阿里云源

    换成国内最快的阿里云源 第一步:备份原来的源文件 cd /etc/apt/ 然后会显示下面的源文件sources.list 输入命令 sudo cp sources.list sources.list ...

  4. CSRF攻击防御方法

    CSRF攻击防御方法 目前防御 CSRF 攻击主要有三种策略: 1. 验证 HTTP Referer 字段: 根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP ...

  5. jdbc打印sql语句-p6spy配置

    @Configuration public class P6SpyConfig { /** * P6数据源包装, 打印SQL语句 */ @Bean public P6DataSourceBeanPos ...

  6. 【PKUWC2018】猎人杀

    题目描述 题目分析 设\(W=\sum\limits_{i=1}^nw_i\),\(A=\sum\limits_{i=1}^nw_i[i\ is\ alive]\),\(P_i\)为下一个打中\(i\ ...

  7. leetcood学习笔记-404-左叶子之和

    题目描述: 方法一:递归 class Solution: def sumOfLeftLeaves(self, root: TreeNode) -> int: if not root: retur ...

  8. Perl 循环

    Perl 循环 有的时候,我们可能需要多次执行同一块代码.一般情况下,语句是按顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推. 编程语言提供了更为复杂执行路径的多种控制结构. 循环语 ...

  9. 【原理】LVM(Logical Volume Manager)动态卷管理

    一张图让你学会LVM   导读 随着科技的进步,人们不知不觉的就进入了大数据的时代,数据的不断增加我们发现我们的磁盘越来越不够用了,接下来就是令人头疼的事情--加硬盘,数据的备份与还原.LVM就是Li ...

  10. 【Bootstrap】 框架 栅格布局系统设计原理

    前提条件(Bootstrap 自带) 首先使用这个布局之前要定义一下代码: 这行代码如果不懂,可以搜索一下,总之大致意思就是,被定义的元素的内边距和边框不再会增加它的宽度,不加入的话排版会有问题. 不 ...