视频加载失败

安吉D3-T2

1542 字
8 分钟
安吉D3-T2
原题呈现

题目描述#

巴蜀地区的地势非常崎岖,山峰耸立.我们将每座山峰依次编号为 11nn,第 ii 座山峰的高度为 hih_i

总共 mm 支施工队,每支施工队的能力各不相同——有些擅长高空作业,有些擅长隧道构建.每支施工队有两个参数:

  • aia_i:最高能施工的高度(即可以处理不超过该高度的山峰);
  • bib_i:最长能修建的隧道长度(即最多可以连续炸掉 bi1b_i - 1 座山来修建隧道,因为出口和入口需要额外加固).

施工队需要从起点 11 出发,修建一条直达 nn 的道路.我们规定 11 号和 nn 号都是平地(高度为 00).

施工队可以从任意一个不超过最高施工高度的高度开始,修建一条高架和隧道结合的道路.一旦确定了道路的初始高度,整条道路的高度就不能再有任何变化.因此:

  • 如果某座山峰的高度低于或等于施工高度,则只需正常修建高架即可;
  • 如果某座山峰的高度高于施工高度,则必须炸山修隧道(即施工队需要在这座山上打通隧道).

请判断每支施工队是否能够胜任这项工作.

输入格式#

第一行包含两个空格分隔的整数 nnmm. 第二行包含 nn 个空格分隔的整数,其中第 ii 个为 hih_i(第 ii 座山峰的高度). 接下来 mm 行,每行包含两个空格分隔的整数 aia_ibib_i,代表第 ii 支施工队的最大施工高度和最长隧道长度.

输出格式#

输出共 mm 行.第 ii 行输出一个整数:如果第 ii 支施工队能够胜任工作,则为 1,否则为 0

样例#

输入 #1#

8 7
0 3 8 5 6 9 0 0
0 5
0 6
6 2
8 1
10 1
5 3
150 7

输出 #1#

0
1
1
0
1
1
1

数据范围#

数据点分值限制
140 pts0n,m50000 \le n, m \le 50001hi,ai1061 \le h_i, a_i \le 10^6
210 pts额外满足 aiai+1a_i \le a_{i+1}bibi+1b_i \le b_{i+1}
3100 pts0n,m1050 \le n, m \le 10^51hi,ai1091 \le h_i, a_i \le 10^91bin11 \le b_i \le n-1

题意可以理解为:求一段序列中一段最大的连续区间 ss,满足:ss每一个数都大于 aia_i,求 ss 的大小 lsl_s,将其和 bib_i 比大小,且多测.

考虑到每个施工队施工的高度越高,障碍越少,且消失的障碍不会回复,因而所需要的 bib_i 也越少.

用一个更加形象的例子,现在有 nn 道题,mm 个学生,每个学生有一个能力值 aia_i,有一个耐力值 b1b_1,每道题有一个难度 hjh_j,现在,让每一名学生来做这些题目,若 j\exists j 使得 ai<hja_i < h_j,则这名学生做不出来第 jj 道题,若有连续 bi1b_i-1 道题这位学生都做不出来,这位学生就会崩溃,求这位学生会不会崩溃.

显然,如果学生 s1s_1 做不出来题目 ii,那么能力弱于 s1s_1s2s_2 也肯定做不出来题目 ii

因此使用离线处理.将每一次询问(即每一个施工队)按 aia_i 从高到低排序,将每一座山也按照高度从高到低排序.模拟一个收容山的并查集,用于记录已经对当前施工队产生影响的障碍,一开始,并查集为空,设未加入并查集最高的山是第 mm 座,高度为 hmh_m,则对于每一次询问:

  • 检查 aia_ihmh_m 的大小关系
    • 若当前询问的 aia_ihmh_m 大或等于(即第 mm 座山,也就是未记录的最高的山都无法对该施工队增加障碍),跳过这个阶段.
    • 否则,说明第 mm 座山成为该施工队施工的新的障碍(由于施工队按照 aia_i 从高到低排列,对靠前者造成影响的山,也会对靠后者造成影响),将 mm 加入并查集,且与第 m1m-1 座和第 m+1m+1 座(如果已经加入并查集的话)合并,并维护每个集合的左边界 ll 和右边界 rr,统计最大的区间 maxmax(初始由于没有山加入到并查集,所以是 0).重复这个操作,直到当前询问的 aia_ihmh_m 大或等于.
  • ans[i]ans[i] 设置为 maxmax

标程

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 100;
int n, m, maxb, ans[N];
struct Mout {
int h, id;
friend bool operator<(const Mout a, const Mout b) { return a.h > b.h; }
};
struct Team {
int h, b, id;
friend bool operator<(const Team a, const Team b) { return a.h > b.h; }
};
struct Node {
int fa, l, r;
} d[N];
// 并查集
struct DSU {
Node *d;
DSU(Node *d) : d(d) {};
// 将节点 x 加入到并查集之中
void active(int x) {
d[x].fa = x;
d[x].l = x, d[x].r = x;
maxb = max(maxb, 1);
}
int find(int x) {
if (d[x].fa == x)
return x;
d[x].fa = find(d[x].fa);
return d[x].fa;
}
void merge(int a, int b) {
a = find(a), b = find(b);
if (a == b)
return;
d[a].fa = b;
d[b].l = min(d[b].l, d[a].l);
d[b].r = max(d[b].r, d[a].r);
maxb = max(maxb, d[b].r - d[b].l + 1);
}
} dsu(d);
Mout h[N];
Team a[N];
int main() {
freopen("mountain.in", "r", stdin);
freopen("mountain.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> h[i].h;
h[i].id = i;
}
for (int i = 1; i <= m; i++) {
cin >> a[i].h >> a[i].b;
a[i].id = i;
}
sort(h + 1, h + n + 1);
sort(a + 1, a + m + 1);
int ptr = 0;
for (int i = 1; i <= m; i++) {
int reqH = a[i].h;
while (h[ptr + 1].h > reqH) {
ptr++;
int curId = h[ptr].id;
dsu.active(curId);
if (dsu.d[curId + 1].fa)
dsu.merge(curId, curId + 1);
if (dsu.d[curId - 1].fa)
dsu.merge(curId, curId - 1);
}
ans[a[i].id] = ((maxb <= a[i].b - 1) ? 1 : 0);
}
for (int i = 1; i <= m; i++) {
cout << ans[i] << endl;
}
}

实际上,对于多次询问,若存在:

如果询问 s1s_1 中,元素 e1e_1 会对该询问的结果产生影响,那么对于所有弱于(或强于) s1s_1s2s_2 ,元素 e1e_1 会对该询问的结果产生影响.

可以考虑使用离线处理 + 排序解决,此时处理后者时可以保留对前者的影响.

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

安吉D3-T2
https://blog.jerrylab.top/posts/problem/anji2026/D3/T2/
作者
Jerry
发布于
2026-08-03
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Jerry
Hello, I'm Jerry.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
最新动态
站点统计
文章
80
分类
3
标签
35
总字数
89,198
运行时长
0
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0