[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
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/ErkkiErkko/p/10373893.html