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

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

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

考虑这个图:

                             

可以看出来,对于每一个上半部分的点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;
}

 

 

 

 

                                      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值