[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; 
}
posted @ 2025-03-26 11:00  WuMin4  阅读(19)  评论(0)    收藏  举报