Walking in Manhattan
原题链接
这题的很明显是对每一个交点做一个类似离散化的操作,只对这些点进行操作。
这样我们很轻松可以拿到 pts 45 但是这个 n 我们不可能把每一个交点都求出来做记忆化之类的操作,而这里其实有点像倍增,但是找不出倍增的规律,其实最重要的就是如何对交点处如何转弯这一个信息进行操作。
我们这只牛在一个横线的交点上,如果这时它向右走,再向上走和它先向上走,再向右走,最终经过的这个交点是一样的,所以我们可以预处理处每一个 x 的下一个会走到的 x' ,y 的下一个走到的 y' 而 \((x,y)\) 的所经过的交点就是 \((x',y')\) 从 $x \rightarrow x' ,y \rightarrow y' $ 的过程就是一次跳,那我们就可以根据这一个倍增,最后可能还会留有一部分步数,我们可以根据之前总共的步数进行分配即可。当然如果这一个点连交点都走不到,那直接特判就可以了。
代码也不是很难写:
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
using namespace std;
const int inf=1e18+7,N=2e5+5;
int n,q;
char s[2];
int st[2][N],cnt1,cnt2;
int f[N][20],g[N][20];
pii query(int x,int y,int d){
int old =d,dx,dy;
int x0=lower_bound(st[0]+1,st[0]+cnt1+1,x)-st[0];
int y0=lower_bound(st[1]+1,st[1]+cnt2+1,y)-st[1];
if(st[1][y0]!=y && st[1][y0]-y>=d)return {x,y+d};
if(st[0][x0]!=x && st[0][x0]-x>=d)return {x+d,y};
d-=(st[0][x0]-x+st[1][y0]-y);
x=x0,y=y0;
for(int i=18;~i;--i){
dx=f[x][i],dy=g[y][i];
if(st[0][dx]-st[0][x]+st[1][dy]-st[1][y]>= d)continue;
d-= st[0][dx]-st[0][x]+st[1][dy]-st[1][y];
x=dx,y=dy;
}
if((old-d)&1) {
dx=f[x][0];
d-=st[0][dx]-st[0][x];
if(d<0)return {st[0][x]+d+st[0][dx]-st[0][x],st[1][y]};
return {st[0][dx],st[1][y]+d};
}
else {
dy=g[y][0];
d-=st[1][dy]-st[1][y];
if(d<0)return {st[0][x],st[1][y]+d+st[1][dy]-st[1][y]};
return {st[0][x]+d,st[1][dy]};
}
}
signed main() {
scanf("%lld%lld",&n,&q);
for(int i=1,x; i<=n; i++) {
scanf("%s%lld",s+1,&x);
if(s[1]=='V')st[0][++cnt1]=x;
else st[1][++cnt2]=x;
}
st[0][++cnt1]=inf;
st[1][++cnt2]=inf;
sort(st[0]+1,st[0]+cnt1+1);
sort(st[1]+1,st[1]+cnt2+1);
for(int j=0; j<=18; j++)f[cnt1][j]=cnt1,g[cnt2][j]=cnt2;
for(int i=cnt1-1;i;i--){
f[i][0]=(st[0][i]+st[0][i+1]&1)?i+1:f[i+1][0];
for(int j=1;j<=18;j++)f[i][j]=f[f[i][j-1]][j-1];
}
for(int i=cnt2-1;i;i--){
g[i][0]=(st[1][i]+st[1][i+1]&1)?i+1:g[i+1][0];
for(int j=1;j<=18;j++)g[i][j]=g[g[i][j-1]][j-1];
}
for(int i=1,x,y,d;i<=q;i++){
scanf("%lld%lld%lld",&x,&y,&d);
pii tmp=query(x,y,d);
printf("%lld %lld\n",tmp.first,tmp.second);
}
return 0;
}

浙公网安备 33010602011771号