XXI Open Cup. Grand Prix of Korea J. Remote Control 相对位置 启发式合并
XXI Open Cup. Grand Prix of Korea J. Remote Control 相对位置 启发式合并
题意
给定长度为\(N\)的包括上下左右的操作序列,在\((0,0)\)点有一障碍物
需要回答\(Q\)个询问,表示从某个起点开始,按照操作序列移动到达的最终位置,若移动到了障碍物,则撤销此次操作
\[1 \leq N \leq 3 \times10^5\\
1 \leq Q \leq 3\times10^5\\
-3\times10^5 \leq x,y \leq 3\times10^5
\]
分析
最终位置实际上是相对于障碍物的相对位置,因此我们只关注相对位置,不难想到把移动物体变换成移动障碍物,最终障碍物所在的位置就可以确定所有询问的最终位置
离线处理出所有询问,考虑如果障碍物碰到某个询问,显然我们不能让障碍物停下(这样其他询问就会出问题),由于我们只关注相对位置,相当于询问向冲突的方向移动一单位。由于可能某个单位有多个询问,需要对受影响的两个位置合并,因此考虑启发式合并。复杂度\(O(nlogn)\)
代码
实现时可以使用vector,但是需要注意用指针来\(O(1)\) 寻址
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef vector<int> VI;
inline ll rd(){
ll x;
scanf("%lld",&x);
return x;
}
map<char,int> dx = {{'R',-1},{'L',1}};
map<char,int> dy = {{'U',-1},{'D',1}};
map<pii,VI*> s;
inline void merge(pii a,pii b){
vector<int>* v1 = s[a];
vector<int>* v2 = s[b];
if(v1 -> size() > v2 -> size()) {
v1 -> insert(v1 -> end(),v2 -> begin(),v2 -> end());
v2 -> clear();
s[b] = v1;
}
else {
v2 -> insert(v2 -> end(),v1 -> begin(),v1 -> end());
v1 -> clear();
}
s.erase(a);
}
int main(){
cin.tie(NULL);
ios_base::sync_with_stdio(false);
int n;
cin >> n;
string ss;
cin >> ss;
int q;
cin >> q;
for(int i = 0; i < q;i++){
int x,y;
cin >> x >> y;
if(!s.count(make_pair(x,y))) s[make_pair(x,y)] = new VI;
s[make_pair(x,y)] -> push_back(i);
}
int x = 0,y = 0;
for(auto c:ss){
int x3 = x + dx[c];
int y3 = y + dy[c];
int x4 = x + 2 * dx[c];
int y4 = y + 2 * dy[c];
if(s.count(make_pair(x3,y3))) {
if(s.count(make_pair(x4,y4))) merge(make_pair(x3,y3),make_pair(x4,y4));
else s[make_pair(x4,y4)] = s[make_pair(x3,y3)],s.erase(make_pair(x3,y3));
}
x = x3;
y = y3;
}
vector<pii> ans(q);
for(auto it:s){
auto b = it.fi;
int bx = b.fi;
int by = b.se;
VI tmp = *it.se;
for(auto itt:tmp) ans[itt] = make_pair(bx - x,by - y);
}
for(auto it:ans){
cout << it.fi << ' ' << it.se << '\n';
}
}