传送门
怎么说呢,这道题目其实不是很难,按照luogu的评级,有紫题的难度适中的那种
思维上其实一般,难的在细节处理,但是我考试时没有想出来正解,只是因为没有花时间在这上面,T3嘛,默认做不出来的,更何况T1是树状数组,谁会想到T3还是树状数组?
70%
按照R从大到小插入,每次看看找H比他大的中最小的那个H做他的“外套”,模仿最长不下降子序列求法
时间复杂度
O
(
Q
n
l
o
g
n
)
O(Qnlogn)
O(Qnlogn)
100%
一堆询问的话,因为我们按照R从大到小插入,那么
R
>
=
A
R>=A
R>=A这个限制就不用管了
按照上面的贪心来做,先找到每个套娃的外套,套娃
i
i
i的高度记为
h
i
h_i
hi,外套高度记为
H
i
H_i
Hi
这个外套是固定不变的
对于每个询问,因为
R
>
=
A
R>=A
R>=A已经处理好,考虑如何算得答案,只要用当前
H
<
=
B
H<=B
H<=B的套娃数减去
H
外
套
<
=
B
H_{外套}<=B
H外套<=B的外套数就是
H
没
有
外
套
的
套
娃
<
=
B
H_{没有外套的套娃}<=B
H没有外套的套娃<=B的数量
用树状数组维护就行了
去掉
R
>
=
A
R>=A
R>=A这个限制只要将询问离线,按照
R
R
R从大到小排序像套娃一样就行了
比较重要的细节是需要将
H
H
H给离散掉,其他小细节挺多的
过了这道题以后去看看std是怎么写的,结果看不懂,感觉我自己的代码写的比std清晰一点
Code:
#include <bits/stdc++.h>
#define maxn 2000010
using namespace std;
struct node{
int r, h, id, H;
}a[maxn], q[maxn], h[maxn];
int ans[maxn], n, Q, tot, d[maxn], p;
int tree1[maxn], tree2[maxn];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c= getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
bool cmp(node x, node y){ return x.r > y.r; }
bool cmp1(node x, node y){ return x.h < y.h; }
int find(int x){
int l = 1, r = tot, sum = 0;
while (l <= r){
int mid = (l + r) >> 1;
if (d[mid] >= x) sum = mid, r = mid - 1; else l = mid + 1;
}
return sum;
}
void upd1(int x){ if (!x) return; for (; x <= p; x += x & -x) ++tree1[x]; }
int query1(int x){ int sum = 0; for (; x; x -= x & -x) sum += tree1[x]; return sum; }
void upd2(int x){ if (!x) return; for (; x <= p; x += x & -x) ++tree2[x]; }
int query2(int x){ int sum = 0; for (; x; x -= x & -x) sum += tree2[x]; return sum; }
int main(){
n = read(), Q = read();
for (int i = 1; i <= n; ++i) a[i].r = read(), h[i].h = read(), h[i].id = i;
for (int i = n + 1; i <= n + Q; ++i) q[i - n].r = read(), h[i].h = read(), h[i].id = i;
for (int i = 1; i <= Q; ++i) q[i].id = i;
sort(h + 1, h + 1 + n + Q, cmp1);
h[0].h = h[1].h + 1;
for (int i = 1; i <= n + Q; ++i)
(h[i].id <= n ? a[h[i].id].h : q[h[i].id - n].h) = h[i].h == h[i - 1].h ? p : ++p;
sort(a + 1, a + 1 + n, cmp);
sort(q + 1, q + 1 + n, cmp);
for (int i = 1; i <= n; ++i){
int tmp = find(a[i].h);
if (tmp) a[i].H = d[tmp], d[tmp] = a[i].h; else
d[++tot] = a[i].h;
}
int j = 1;
for (int i = 1; i <= Q; ++i){
while (a[j].r >= q[i].r && j <= n) upd1(a[j].h), upd2(a[j++].H);
ans[q[i].id] = query1(q[i].h) - query2(q[i].h);
}
for (int i = 1; i <= Q; ++i) printf("%d\n", ans[i]);
return 0;
}

本文介绍了一种使用树状数组解决特定套娃问题的方法。该问题要求找到一系列套娃的最大数量,使得每个套娃都可以放入另一个更大的套娃中,并且满足一定的高度和宽度条件。文章详细解释了算法思路,包括按宽度排序插入、查找匹配的“外套”套娃以及通过树状数组维护状态等关键步骤。

被折叠的 条评论
为什么被折叠?



