1 条题解

  • 0
    @ 2025-8-24 22:03:08

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar T_Q_X
    AFO

    搬运于2025-08-24 22:03:08,当前版本为作者最后更新于2020-10-20 09:34:03,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目链接

    洛谷P4739

    题目翻译:

    你正在模拟无人机探索一个不稳定的环状行星的过程。技术上说,无人机正在穿过一个环形网格———一个在两维上都首尾环绕在一起的矩形网格。格子的行号从上到下依次编号为11rr,列号从上到下依次编号为11cc。每个格子还有一个海拔——这是个正数。

    无人机一开始位于第一行第一列的格子。每一步,无人机会考虑这样三个格子:右边、右上方、右下方(注意这个网格首尾相接)。无人机会飞到它们之中海拔最高的一个格子。模拟的过程中,共有两种可能的操作:

    movemove kk无人机移动k步

    changechange aa bb eeaa行第bb列的格子海拔修改为ee

    在每次movemove操作后,你都需要立刻找到无人机的位置。你可以认为,每次移动的三个目标位置海拔互不相同,因此每一步移动都是良定义的。

    solution

    每次移动的步数kk很大,所以可以联想到倍增跳法,即每次跳2k2^k步。

    但步数不太好维护,我们考虑将移动kk步转化为先暴力跳到第一列,再从第一列出发跳若干圈,最后在暴力跳剩下的不到一圈的步数。显然2段暴力跳的复杂度仅为O(c)O(c),可以接受

    那么问题转化为了要维护从第一列的每一个位置出发跳2k2^k圈后所处的位置。本题在yy轴上的跳法不确定,但在xx轴上一直是每次向右移动一格,于是可以在列上建立线段树,每个节点(设对应的列为l,rl,r)维护第ll列上每个位置,跳到第r+1r+1列后所处的位置,就可以

    t[p][i]=t[p<<1|1][t[p<<1][i]] 
    

    实现转移(其中t[p][i]t[p][i]表示处在第ii行的点,跳过pp对应的这段区间后所处的位置,在代码中是T[p].t[i]T[p].t[i])

    于是根节点维护的答案就是第一列中的每个位置跳一圈后所处的位置,接下来的只不过是倍增基本套路。

    每次对(x,y)(x,y)的修改只会影响第x1x-1列维护的答案,等于是线段树中的单点修改,复杂度O(rlog(c))O(rlog(c))

    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
    上传者