[ABC385D] Santa Claus 2
[ABC385D] Santa Claus 2
题意
平面上有 \(n\) 个点,有 \(m\) 个操作,每次操作可以向上下左右移动若干格,问 \(m\) 个操作后的坐标与经过的点的数量(多次经过不算)。
思路
个人认为史上最恶心 D 题,思路不难想,代码就是依托。
容易发现每次移动后要不 \(x\) 坐标不变,要不 \(y\) 坐标不变,于是可以用 \(\text{set}\) 对于每个 \(x\) 坐标和 \(y\) 坐标存下 \(x_i=x\) 和 \(y_i=y\) 的点,这样在每次移动时只需要遍历在 \(x\) 坐标上或在 \(y\) 坐标上的点并删除即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,m,sx,sy,ans,lx,ly;
unordered_map<int,int> xx,yy;
map<pair<int,int>,bool> vis;
set<int> mx[200005],my[200005];
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>m>>sx>>sy;
for(int x,y,i=1;i<=n;i++){
cin>>x>>y;
if(!xx[x]) xx[x]=++lx;
if(!yy[y]) yy[y]=++ly;
mx[xx[x]].insert(y);
my[yy[y]].insert(x);
}
vector<int> rem;
for(int i=1;i<=m;i++){
rem.clear();
char s;
int x,tx,ty;
cin>>s>>x;
tx=xx[sx],ty=yy[sy];
if(s=='U'){
if(!mx[tx].empty())
for(auto it=mx[tx].lower_bound(sy);it!=mx[tx].end()&&*it<=sy+x;it++){
if(!vis[{sx,*it}])
ans++,vis[{sx,*it}]=true;
rem.push_back(*it);
}
for(int v:rem)
mx[tx].erase(v);
sy+=x;
}
if(s=='D'){
if(!mx[tx].empty())
for(auto it=--mx[tx].upper_bound(sy);*it>=sy-x;it--){
if(!vis[{sx,*it}])
ans++,vis[{sx,*it}]=true;
rem.push_back(*it);
if(it==mx[tx].begin()) break;
}
for(int v:rem)
mx[tx].erase(v);
sy-=x;
}
if(s=='L'){
if(!my[ty].empty())
for(auto it=--my[ty].upper_bound(sx);*it>=sx-x;it--){
if(!vis[{*it,sy}])
ans++,vis[{*it,sy}]=true;
rem.push_back(*it);
if(it==my[ty].begin()) break;
}
for(int v:rem)
my[ty].erase(v);
sx-=x;
}
if(s=='R'){
if(!my[ty].empty())
for(auto it=my[ty].lower_bound(sx);it!=my[ty].end()&&*it<=sx+x;it++){
if(!vis[{*it,sy}])
ans++,vis[{*it,sy}]=true;
rem.push_back(*it);
}
for(int v:rem)
my[ty].erase(v);
sx+=x;
}
}
cout<<sx<<" "<<sy<<" "<<ans;
return 0;
}

浙公网安备 33010602011771号