LOJ杂题

P2880. 「JOISC 2014 Day3」稻草人

cdq分治裸体。
但有一位哲人说过:“裸体就是身体。”尤其对于我这种算法采集,写这都用了一晚上。
大致思路:
将当前区间分为(l,mid),(mid+1,r)两部分往下分治,处理出各自区间内的答案;
随后按y单调下降排序,计算左区间内点为矩形左下角,右区间内点为右上角的情况。
我们发现右区间内能利用的点纵坐标单调下降,横坐标单调上升。
按上面思路对两个区间各建一个单调栈,左区间x单调递增,右区间x单调递减;
又发现对于左区间单调栈的一个点 i,有贡献的右区间点 j 满足:

\[p[i-1].y<p[j].y<p[i].y \]

处理出符合该条件的右区间点数,加入答案即可。
参考博客:https://www.cnblogs.com/cjyyb/p/8419102.html
\(code\)

#include <bits/stdc++.h>
#define ll long long
#define rgi register int
using namespace std;
const int M=2e5+7,inf=1e9+7;
inline int read(){
	int w=0,r=1;char c=getchar();
	while(!(isdigit(c)||c=='-'))c=getchar();
	if(c=='-')r=-1,c=getchar();
	while(isdigit(c))w=w*10+c-'0',c=getchar();
	return w*r;
}
int n,stk1[M],stk2[M];
struct point{
	int x,y;
}p[M];
ll ans;
bool cmp1(point aa,point bb){
	return aa.x<bb.x;
}
bool cmp2(point aa,point bb){
	return aa.y>bb.y;
}
void cdq(int l,int r){
	if(l==r)return;
	int mid=(l+r)>>1;
	cdq(l,mid),cdq(mid+1,r);
	sort(p+l,p+mid+1,cmp2),sort(p+mid+1,p+r+1,cmp2);
	int tot1=0,tot2=0,ii=mid+1; 
	for(int i=l;i<=mid;i++){ 
		while(ii<=r&&p[ii].y>p[i].y){
			while(tot2&&p[ii].x<p[stk2[tot2]].x)tot2--;
			stk2[++tot2]=ii++;
//			printf("8\n");
		}
		while(tot1>0&&p[i].x>p[stk1[tot1]].x)tot1--;//,printf("9\n");
		stk1[++tot1]=i;
		if(tot1==1)ans+=tot2;
		else{
			int l1=1,r1=tot2,mid,an=tot2+1;
			while(l1<=r1){
//				printf("7\n");
				mid=(l1+r1)>>1;
				if(p[stk2[mid]].y>p[stk1[tot1-1]].y)l1=mid+1;
				else an=mid,r1=mid-1;
			}
			ans+=tot2-an+1;
		}
//		printf("%d %d    %d %d\n",l,r,i,ans);
	}
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)p[i]=(point){read(),read()};
	sort(p+1,p+n+1,cmp1);
	cdq(1,n);
	printf("%lld\n",ans);
	return 0;
}
/*
4
0 0
2 2
3 4
4 3
*/
posted @ 2021-11-05 22:51  wcy2006  阅读(36)  评论(0)    收藏  举报