1. 1. 题目
  2. 2. 题解
    1. 2.1. 暴力做法
    2. 2.2. 优化一点
    3. 2.3. 再优化一点
  3. 3.
  4. 4. 代码

题目

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表写炸了。。。。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#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;
}