AT2542 誘拐 2 (Abduction 2)
一个很妙的题
思路
1. 暴力
我们直接从每个起点向各个方向出发,暴力求出能跑到的最大距离。复杂度为 \(2^{\max\{n, m\}}\)
2. 优化
显然,我们可以发现,我们直走到一个车流量比当前的路要大的路,才需要进行转弯。因此,我们可以对横路和纵路分别建立一棵线段树,里面存的是 \([l,r]\) 的路中最大的流量,通过类似于线段树二分的方法就可以找到最近的一条可转弯的路(当然,通过 ST表 进行倍增也可以做到)
3. 正解
但如果我们只优化直走的道路,这样的优化也并不大
我们又注意到,很多点是会重复经过的,因此我们可以用记忆化搜索,设 \(f_{k,i,j}\) ,\(k=0/1\) 表示南北或东西,\((i,j)\) 表示当前的坐标
我们不能开到 \(50000\times 50000\times 2\),但其实这个数组并不会用满,我们可以用 map 来优化空间
时间复杂度就是 \(O((n+m)q)\)
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = r[i].nxt)
inline int reads()
{
int sign = 1, re = 0; char c = getchar();
while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
return sign * re;
}
int n, m, q, a[50005], b[50005];
struct Seg_Tree
{
int tr[200005];
#define ls (now << 1)
#define rs ((now << 1) | 1)
void build(int now, int l, int r, int a[])
{
if(l == r) {tr[now] = a[l]; return;}
int mid = (l + r) >> 1;
build(ls, l, mid, a), build(rs, mid + 1, r, a);
tr[now] = std::max(tr[ls], tr[rs]);
}
int ql(int now, int l, int r, int p, int val)
{
if(p <= l || tr[now] <= val) return 0;
if(l == r) return l;
int mid = (l + r) >> 1;
int re = ql(rs, mid + 1, r, p, val);
if(re) return re;
return ql(ls, l, mid, p, val);
}
int qr(int now, int l, int r, int p, int val)
{
if(r <= p || tr[now] <= val) return 0;
if(l == r) return l;
int mid = (l + r) >> 1;
int re = qr(ls, l, mid, p, val);
if(re) return re;
return qr(rs, mid + 1, r, p, val);
}
#undef ls
#undef rs
}r, c;
std::map<int, LL> f[2][50005];
LL solve(int x, int y, int ty) // 0 表示南北,1 表示东西
{
if(f[ty][x][y]) return f[ty][x][y];
LL re = 0;
if(!ty)
{
int U = r.ql(1, 1, n, x, b[y]), D = r.qr(1, 1, n, x, b[y]);
if(U) re = std::max(re, 1ll * (x - U) + solve(U, y, 1));
else re = std::max(re, 1ll * (x - 1));
if(D) re = std::max(re, 1ll * (D - x) + solve(D, y, 1));
else re = std::max(re, 1ll * (n - x));
}
else
{
int L = c.ql(1, 1, m, y, a[x]), R = c.qr(1, 1, m, y, a[x]);
if(L) re = std::max(re, 1ll * (y - L) + solve(x, L, 0));
else re = std::max(re, 1ll * (y - 1));
if(R) re = std::max(re, 1ll * (R - y) + solve(x, R, 0));
else re = std::max(re, 1ll * (m - y));
}
return f[ty][x][y] = re;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
n = reads(), m = reads(), q = reads();
FOR(i, 1, n) a[i] = reads();
FOR(i, 1, m) b[i] = reads();
r.build(1, 1, n, a), c.build(1, 1, m, b);
while(q--)
{
int x = reads(), y = reads();
printf("%lld\n", std::max(solve(x, y, 0), solve(x, y, 1)));
}
return 0;
}

浙公网安备 33010602011771号