题解:P10137 [USACO24JAN] Walking in Manhattan G
zhang_kevin · · 题解
神仙倍增题。
注意到,同一条直线上的两个点在进行“两次转弯”后一定还在同一直线(如果能到达),因此令
显然,两条相邻直线间距的奇偶性决定了
计算完倍增数组后,就可以解决问题了。
首先,对于一个点,我们可以二分出离他最近的十字路口。我们以这个十字路口作为新的起点,注意特判走不到十字路口的情况。
其次,只要还可以进行“两次转弯”,我们就根据倍增数组进行。这样可以在
最后,根据已经走过的路程计算终点即可。
参考代码(时间复杂度
#include<bits/stdc++.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<immintrin.h>
#define int long long
namespace detail {
// Fast IO by masonxiong (%%%)
// DON'T copy my code
// But if you want brown tag......
};
class Scanner {
// Fast Input
} cin;
class Printer {
// Fast Output
} cout;
int n, q, f[200005][20], g[200005][20];
std::vector<int> heng, shuu;
signed main(){
cin >> n >> q;
for(int i = 1; i <= n; i++){
char ch; cin >> ch;
if(ch == 'H'){
int x; cin >> x;
heng.push_back(x);
}else{
int x; cin >> x;
shuu.push_back(x);
}
}
heng.push_back(1000000086 << 1), shuu.push_back(1000000086 << 1);
sort(heng.begin(), heng.end()), sort(shuu.begin(), shuu.end());
for(int j = 0; j < 20; j++){
f[heng.size() - 1][j] = heng.size() - 1;
for(int i = (int)heng.size() - 2; ~i; i--){
if(j == 0){
f[i][j] = (heng[i + 1] - heng[i]) & 1 ? i + 1 : f[i + 1][0];
}else{
f[i][j] = f[f[i][j - 1]][j - 1];
}
}
g[shuu.size() - 1][j] = shuu.size() - 1;
for(int i = (int)shuu.size() - 2; ~i; i--){
if(j == 0){
g[i][j] = (shuu[i + 1] - shuu[i]) & 1 ? i + 1 : g[i + 1][0];
}else{
g[i][j] = g[g[i][j - 1]][j - 1];
}
}
}
// for(int i = 0; i < (int)heng.size(); i++){
// for(int j = 0; j < 20; j++){
// cout << f[i][j] << ' ';
// }
// cout << '\n';
// }
// cout << '\n';
// for(int i = 0; i < (int)shuu.size(); i++){
// for(int j = 0; j < 20; j++){
// cout << g[i][j] << ' ';
// }
// cout << '\n';
// }
while(q--){
int x, y, d; cin >> x >> y >> d;
int heng0 = std::lower_bound(heng.begin(), heng.end(), y) - heng.begin();
int shuu0 = std::lower_bound(shuu.begin(), shuu.end(), x) - shuu.begin();
int dis = 0;
//Step 1
// cout << "Step 1 Starting!" << '\n';
if(y != heng[heng0]){
int runn = heng[heng0] - y;
if(runn >= d){
cout << x << ' ' << y + d << '\n';
continue;
}
d -= runn, dis += runn;
y = heng[heng0];
}
if(x != shuu[shuu0]){
int runn = shuu[shuu0] - x;
if(runn >= d){
cout << x + d << ' ' << y << '\n';
continue;
}
d -= runn, dis += runn;
x = shuu[shuu0];
}
//Step 2
// cout << "Step 2 Starting!" << '\n';
for(int i = 19; ~i; i--){
int x = f[heng0][i], y = g[shuu0][i];
int runn = (heng[x] - heng[heng0]) + (shuu[y] - shuu[shuu0]);
if(runn <= d){
d -= runn, dis += runn;
heng0 = x, shuu0 = y;
}
}
//Step 3
// cout << "Step 3 Starting!" << '\n';
if(dis & 1){
int runn = shuu[g[shuu0][0]] - shuu[shuu0];
if(runn >= d){
cout << shuu[shuu0] + d << ' ' << heng[heng0] << '\n';
}else{
cout << shuu[g[shuu0][0]] << ' ' << heng[heng0] + d - runn << '\n';
}
}else{
int runn = heng[f[heng0][0]] - heng[heng0];
if(runn >= d){
cout << shuu[shuu0] << ' ' << heng[heng0] + d << '\n';
}else{
cout << shuu[shuu0] + d - runn << ' ' << heng[f[heng0][0]] << '\n';
}
}
}
return 0;
}