[BZOJ4237]稻草人:CDQ分治+单调栈

分析

\(y\)排序后CDQ分治,可以发现每个点可以影响的是\(x\)坐标的一段区间,可以使用扫描线+单调栈,在单调栈上二分即可解决,时间复杂度\(O(n \log^2 n)\)

通过归并排序可以显著减小常数。

代码

#include <bits/stdc++.h>
#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

const int MAXN=200005;

int n,sta1[MAXN],sta2[MAXN];
LL ans;
struct man{
	int x,y;
}a[MAXN],b[MAXN];

inline bool cmpx(man A,man B){return A.x<B.x;}
inline bool cmpy(man A,man B){return A.y<B.y;}
inline bool cmp(int A,int B){return a[A].x<a[B].x;}

void mergesort(int l,int r){
	int mid=((l+r)>>1),top=0,top1=l,top2=mid+1;
	while(top<r-l+1){
		if(top2==r+1||(top1<=mid&&a[top1].x<a[top2].x)) b[++top]=a[top1],++top1;
		else b[++top]=a[top2],++top2;
	}
	memcpy(a+l,b+1,(r-l+1)*8);
}

void cdq(int l,int r){
	if(l==r) return;
	int mid=((l+r)>>1);
	cdq(l,mid);
	cdq(mid+1,r);
	int top1=0,top2=0,ptr=l-1;
	rin(i,mid+1,r){
		while(top1&&a[i].y<a[sta1[top1]].y) --top1;
		while(ptr<mid&&a[ptr+1].x<a[i].x){
			++ptr;
			while(top2&&a[ptr].y>a[sta2[top2]].y) --top2;
			sta2[++top2]=ptr;
		}
		ans+=sta2+top2+1-std::lower_bound(sta2+1,sta2+top2+1,sta1[top1],cmp);
		sta1[++top1]=i;
	}
	if(l!=1||r!=n) mergesort(l,r);
}

int main(){
	n=read();
	rin(i,1,n) a[i].x=read(),a[i].y=read();
	std::sort(a+1,a+n+1,cmpy);
	cdq(1,n);
	printf("%lld\n",ans);
	return 0;
}

posted on 2019-02-14 12:09  ErkkiErkko  阅读(163)  评论(0编辑  收藏  举报