BZOJ 4237 稻草人:CDQ分治+单调栈上二分

Posted wx62be51b466b43

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 4237 稻草人:CDQ分治+单调栈上二分相关的知识,希望对你有一定的参考价值。

1.​​题目链接​​。这个题目乍一看像是求一个偏序,但是好像有不是那么回事,因为两个点之间不能有第三个点,如何避免这一点呢?

2.考虑对y分治,首先按照y排序。然后可以把序列分为两部分,一部分在上面,一部分在下面。枚举上半部分的点,计算左下方有多少个点符合条件,这样分治的过程中统计答案即可。但是怎么计算左下方的点呢?

考虑这个图:

                              【BZOJ

可以看出来,对于每一个上半部分的点A,把下半部分所有x小于它的点加入一个y坐标单调递减的单调栈,对于上半部分,因为只有这个点左上角的点对它才没有影响,维护一个y单调递增的单调栈,这样每次加入一个点,直接在下面点的单调栈里二分即可。这里需要注意,每一层递归完成之后,需要对x做归并排序,保证x是有序的。这样才能二分点的位置。

#include<bits/stdc++.h>
#define N 200005
#define ll long long
using namespace std;
int n, m, p[N], q[N]; struct node int x, y; a[N], b[N]; ll ans;
bool cmpy(node u, node v) return u.y < v.y;
int getans(int x, int l, int r)
while (l + 1 < r)
int mid = (l + r) >> 1;
if (a[q[mid]].x < x) l = mid;
else r = mid;

return l;

void cdq(int l, int r)
if (l == r) return;
int mid = (l + r) >> 1;
cdq(l, mid);
cdq(mid + 1, r);
int tp1 = 0, tp2 = 0, j = l, k;
for (int i = mid + 1; i <= r; i++)

while (tp1 && a[i].y < a[p[tp1]].y) tp1--;
p[++tp1] = i;
for (; a[j].x < a[i].x && j <= mid; j++)
while (tp2 && a[j].y > a[q[tp2]].y) tp2--;
q[++tp2] = j;

ans += tp2 - getans(a[p[tp1 - 1]].x, 0, tp2 + 1);

j = l; k = mid + 1;
for (int i = l; i <= r; i++)
b[i] = (j <= mid && a[j].x<a[k].x || k>r) ? a[j++] : a[k++];
for (int i = l; i <= r; i++) a[i] = b[i];

int main()

scanf("%d", &n);
for (int i = 1; i <= n; i++)

scanf("%d%d", &a[i].x, &a[i].y);

sort(a + 1, a + n + 1, cmpy);
cdq(1, n);
printf("%lld\\n", ans);
return 0;

 

 

 

 

                                      


以上是关于BZOJ 4237 稻草人:CDQ分治+单调栈上二分的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4237: 稻草人

bzoj 4237 稻草人

bzoj 4237: 稻草人 -- CDQ分治

[bzoj4237]稻草人

BZOJ4237 稻草人 分治 单调栈

4237: 稻草人