1 条题解
-
0
自动搬运
来自洛谷,原作者为

T_Q_X
AFO搬运于
2025-08-24 22:03:08,当前版本为作者最后更新于2020-10-20 09:34:03,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目链接
题目翻译:
你正在模拟无人机探索一个不稳定的环状行星的过程。技术上说,无人机正在穿过一个环形网格———一个在两维上都首尾环绕在一起的矩形网格。格子的行号从上到下依次编号为到,列号从上到下依次编号为到。每个格子还有一个海拔——这是个正数。
无人机一开始位于第一行第一列的格子。每一步,无人机会考虑这样三个格子:右边、右上方、右下方(注意这个网格首尾相接)。无人机会飞到它们之中海拔最高的一个格子。模拟的过程中,共有两种可能的操作:
无人机移动k步
第行第列的格子海拔修改为。
在每次操作后,你都需要立刻找到无人机的位置。你可以认为,每次移动的三个目标位置海拔互不相同,因此每一步移动都是良定义的。
solution
每次移动的步数很大,所以可以联想到倍增跳法,即每次跳步。
但步数不太好维护,我们考虑将移动步转化为先暴力跳到第一列,再从第一列出发跳若干圈,最后在暴力跳剩下的不到一圈的步数。显然2段暴力跳的复杂度仅为,可以接受
那么问题转化为了要维护从第一列的每一个位置出发跳圈后所处的位置。本题在轴上的跳法不确定,但在轴上一直是每次向右移动一格,于是可以在列上建立线段树,每个节点(设对应的列为)维护第列上每个位置,跳到第列后所处的位置,就可以
t[p][i]=t[p<<1|1][t[p<<1][i]]实现转移(其中表示处在第行的点,跳过对应的这段区间后所处的位置,在代码中是)
于是根节点维护的答案就是第一列中的每个位置跳一圈后所处的位置,接下来的只不过是倍增基本套路。
每次对的修改只会影响第列维护的答案,等于是线段树中的单点修改,复杂度
code
#include<bits/stdc++.h> using namespace std; const int N=5010; int a[N][N],ans[N][N],R,C,m,to[N][32]; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*f; } struct SGT{ struct tree{ int t[N]; }T[N<<2]; #define lc (p<<1) #define rc (p<<1|1) #define mid (l+r>>1) inline void pushup(int p){ for(int i=1;i<=R;++i) T[p].t[i]=T[rc].t[T[lc].t[i]]; } inline void build(int p,int l,int r){ if(l==r){ for(int i=1;i<=R;++i) T[p].t[i]=ans[l][i]; return ; } build(lc,l,mid); build(rc,mid+1,r); pushup(p); } inline void update(int p,int l,int r,int x){ if(l==r){ for(int i=1;i<=R;++i) T[p].t[i]=ans[l][i]; return ; } if(x<=mid) update(lc,l,mid,x); else update(rc,mid+1,r,x); pushup(p); } #undef lc #undef rc #undef mid }T; inline void work(int &x,int &y){ int yy=y==C?1:y+1,x1=x>1?x-1:R,x2=x,x3=x==R?1:x+1; int ans=a[x1][yy],pos=x1; if(a[x2][yy]>ans) ans=a[x2][yy],pos=x2; if(a[x3][yy]>ans) ans=a[x3][yy],pos=x3; x=pos;y=yy; } int main(){ R=read();C=read(); for(int i=1;i<=R;++i) for(int j=1;j<=C;++j) a[i][j]=read(); for(int i=1;i<=R;++i){ for(int j=1;j<=C;++j){ int x=i,y=j;work(x,y); ans[j][i]=x; } } T.build(1,1,C); for(int i=1;i<=R;++i) to[i][0]=T.T[1].t[i]; for(int j=1;j<=30;++j) for(int i=1;i<=R;++i) to[i][j]=to[to[i][j-1]][j-1]; m=read(); int nx=1,ny=1; while(m--){ char s[10];scanf("%s",s); if(s[0]=='c'){ int x=read(),y=read(),e=read(); a[x][y]=e;y=y>1?y-1:C; for(int i=1;i<=R;++i){ int t1=i,t2=y; work(t1,t2); ans[y][i]=t1; } T.update(1,1,C,y); for(int i=1;i<=R;++i) to[i][0]=T.T[1].t[i]; for(int j=1;j<=30;++j) for(int i=1;i<=R;++i) to[i][j]=to[to[i][j-1]][j-1]; } if(s[0]=='m'){ int k=read(); while(k&&ny!=1) work(nx,ny),k--; int circle=k/C;k=k%C; for(int i=30;i>=0;--i) if(circle&(1<<i)) circle^=(1<<i),nx=to[nx][i]; while(k--) work(nx,ny); printf("%d %d\n",nx,ny); } } return 0; }
- 1
信息
- ID
- 3723
- 时间
- 8000ms
- 内存
- 500MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者