1350 字
7 分钟
[JOI 2022 Final] 铁路旅行 2 (Railway Trip 2)
2023-10-10

题目#

IOI 铁路公司在一条铁轨上运营线路。铁轨为一条直线,该铁轨上有 NN 个车站,编号为 1N1 \sim N。车站 ii 与车站 i+1i + 1 之间由一条铁轨直接连接。

IOI 铁路公司正在运营 MM 条线路,编号为 1M1 \sim M。线路 jj 的起点为 AjA_j,终点为 BjB_j,列车在每一站均会停靠,即如果 Aj<BjA_j < B_j,一列 jj 号线的列车会按顺序在车站 Aj,Aj+1,,BjA_j, A_j + 1, \ldots, B_j 停靠。如果 Aj>BjA_j > B_j,一列 jj 号线的列车会按顺序在车站 Aj,Aj1,,BjA_j, A_j - 1, \ldots, B_j 停靠。

JOI 君是一个旅行者。他有 QQ 个旅行计划。在第 kk 个旅行计划中他计划从车站 SkS_k 通过乘坐列车前往车站 TkT_k

然而,JOI 君因长途跋涉而疲惫不堪。他希望他乘坐的列车均有空座以便休息。因此 JOI 君决定,只有当某条线路的起点站是第 KK 个或更早的车站时,他才会在该站乘坐该条线路的列车。换句话说,对于线路 jj,如果 Aj<BjA_j < B_j,那么他只会在车站 Aj,Aj+1,,min{Aj+K1,Bj1}A_j, A_j + 1, \ldots, \min \{ A_j + K - 1, B_j - 1 \} 乘上线路 jj 的列车。如果 Aj>BjA_j > B_j,那么他只会在车站 Aj,Aj1,,max{AjK+1,Bj+1}A_j, A_j - 1, \ldots, \max \{ A_j - K + 1, B_j + 1 \} 乘上线路 jj 的列车。

在这些条件下,JOI 君希望尽量减少乘坐火车的次数。

给出 IOI 铁路公司的线路信息和 JOI 君的计划,写一个程序计算对于 JOI 君的每一个计划,他所需的最小乘车次数。

对于 100%100 \% 的数据,2N1052 \le N \le {10}^51KN11 \le K \le N - 11M2×1051 \le M \le 2 \times {10}^51Q5×1041 \le Q \le 5 \times {10}^41Aj,Bj,Sk,TkN1 \le A_j, B_j, S_k, T_k \le NAjBjA_j \ne B_jSkTkS_k \ne T_k(Aj,Bj)(Ak,Bk)(A_j, B_j) \ne (A_k, B_k)jkj \ne k),(Sk,Tk)(Sl,Tl)(S_k, T_k) \ne (S_l, T_l)klk \ne l)。

题解#

为了学习算法写的这道题,抄的题解

暴力做法#

从起点开始深搜,复杂度爆炸

优化一点#

f[i][j]表示从i点走j次路线所能到达的最远的地方(pair,左右端点)

预处理出所有的f[i][j],枚举f[i][j - 1]中的所有点k,看f[k][1]能到达的左右最大值

复杂度O(n2m)O(n^2m),会炸

再优化一点#

看到这种走走停停的题,考虑能不能倍增

f[i][j]表示i点走2j2^j次路线所能到达的最远的地方(pair,左右端点)

考虑转移,枚举f[i][j - 1]的每个位置k,找到f[k][j - 1]能到达的左右最大值

显然不能暴力枚举找最大值,可以对于每一个2^j代表的j建立一个st表,(因为没有修改),然后可以做了

结果查询怎么办呢

很像lca,枚举f[起点][w]w从大到小枚举,如果到得了终点,那么w继续减,直到到不了为止。最后如果结束的点没法到终点,输出-1,否则res+1即可

#

st表写炸了。。。。

代码#

#include<bits/stdc++.h>
#define PII pair<int, int>
#define l first
#define r second
using namespace std;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
PII up_route[M], down_route[M];
int upcnt, downcnt;
int fl[N][20], fr[N][20];
int n, m, k;
int qwq[M], hh = 1, tt = 0;
bool cmp(PII A, PII B)
{
return A.second > B.second;
}
const int LOG = 20;
struct ST
{
int st[N][LOG];
void init(int k,int lorr)
{
if(lorr == 0)
{
memset(st, 0x3f, sizeof st);
}
for(int i = 1;i <= n;i++)
st[i][0] = ((!lorr) ? (fl[i][k]) : (fr[i][k]));
}
void prepare(int lorr)
{
for(int j = 1;j < LOG;j++)
{
for(int i = 1;i + (1 << j) - 1 <= n;i++)
{
st[i][j] = ((!lorr) ? min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]) : max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]));
}
}
}
int query(int l, int r, int lorr)
{
int lllooojjj = log2(r - l + 1);
return ((!lorr) ? min(st[l][lllooojjj], st[r - (1 << lllooojjj) + 1][lllooojjj]) : max(st[l][lllooojjj], st[r - (1 << lllooojjj) + 1][lllooojjj]));
}
}s[20][2];//0代表fl,1代表fr
int ask(int b, int t)
{
int res = 0;
int l = b, r = b;
for(int k = 19;k >= 0;k--)
{
int L = s[k][0].query(l, r, 0);
int R = s[k][1].query(l, r, 1);
if(L <= t && t <= R) continue;
// cout << k << " " << L << " " << R << endl;
res += (1 << k);
l = L, r = R;
}
int L = s[0][0].query(l, r, 0);
int R = s[0][1].query(l, r, 1);
if(L <= t && t <= R) return res + 1;
return -1;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> k;
cin >> m;
int u, v;
for(int i = 1;i <= m;i++)
{
cin >> u >> v;
if(u < v)
{
up_route[++upcnt] = make_pair(u, v);
}
else
{
down_route[++downcnt] = make_pair(v, u);
}
}
if(upcnt >= 1)
sort(up_route + 1, up_route + upcnt + 1);
if(downcnt >= 1)
sort(down_route + 1, down_route + downcnt + 1, cmp);
for(int i = 1;i <= n;i++)
fl[i][0] = fr[i][0] = i;
if(upcnt >= 1)
for(int i = 1, j = 1;i <= n;i++)
{
while(j <= upcnt && up_route[j].l <= i)
{
while(hh <= tt && up_route[j].r >= up_route[qwq[tt]].r)
{
tt --;
}
qwq[++tt] = j;
j++;
}
while(hh <= tt && up_route[qwq[hh]].l + k - 1 < i/*!!!*/)
{
hh++;
}
if(hh > tt) continue;/*!!!*/
fr[i][0] = max(fr[i][0], up_route[qwq[hh]].r);
}
memset(qwq, 0, sizeof qwq);
hh = 1, tt = 0;
if(downcnt >= 1)
for(int i = n, j = 1;i >= 1;i--)
{
while(j <= downcnt && down_route[j].r >= i)
{
while(hh <= tt && down_route[j].l <= down_route[qwq[tt]].l)
{
tt --;
}
qwq[++tt] = j;
j++;
}
while(hh <= tt && down_route[qwq[hh]].r - k + 1 > i/*!!!*/)
{
hh++;
}
if(hh > tt) continue;/*!!!*/
fl[i][0] = min(fl[i][0], down_route[qwq[hh]].l);
}
s[0][0].init(0, 0);
s[0][0].prepare(0);
s[0][1].init(0, 1);
s[0][1].prepare(1);
for(int k = 1;k < 20;k++)
{
for(int i = 1;i <= n;i++)
{
fl[i][k] = s[k - 1][0].query(fl[i][k - 1], fr[i][k - 1], 0);
fr[i][k] = s[k - 1][1].query(fl[i][k - 1], fr[i][k - 1], 1);
}
s[k][0].init(k, 0);
s[k][0].prepare(0);
s[k][1].init(k, 1);
s[k][1].prepare(1);
}
int Q;
cin >> Q;
int s, t;
while(Q -- )
{
cin >> s >> t;
cout << ask(s, t) << "\n";
}
return 0;
}
[JOI 2022 Final] 铁路旅行 2 (Railway Trip 2)
https://blog.histcat.top/posts/p8163/
作者
Histcat
发布于
2023-10-10
许可协议
CC BY-NC-SA 4.0