原文链接https://www.cnblogs.com/zhouzhendong/p/8682572.html
题目传送门 - BZOJ4237
题意
平面上有$n(n\leq 2\times 10^5)$个整点(坐标范围在$[0,10^9]$之间)。
第$i$个点$p_i$的坐标是$(x_i,y_i)$。
如果有一对点$p_i$和$p_j$,满足$x_i<x_j,y_i<y_j$,而且以这两个点为左下角和右上角所围城的矩形内不包含任何整点(边界上面不算),那么他们对答案的贡献为1。
求答案。
题解
对于$x$坐标分治,然后单调栈解决跨越中线两端的点的贡献即可。
好像听好写的,不详细介绍了。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=200005;
struct Point{
int x,y;
void get(){
scanf("%d%d",&x,&y);
}
}p[N],q[N];
int n,Lstack[N],Rstack[N],Ltop,Rtop;
LL ans=0;
bool cmpx(Point a,Point b){
return a.x<b.x;
}
void solve(int xL,int xR,int L,int R){
if (L>=R)
return;
int xmid=(xL+xR)>>1,mid=R;
while (mid>=L&&p[mid].x>xmid)
mid--;
solve(xL,xmid,L,mid);
solve(xmid+1,xR,mid+1,R);
Ltop=Rtop=0;
Lstack[0]=Rstack[0]=0;
q[0].y=-1;
for (int i=L,l=L,r=mid+1;i<=R;i++)
if (r>R||(l<=mid&&p[l].y<=p[r].y)){
q[i]=p[l++];
while (Ltop>0&&q[Lstack[Ltop]].x<q[i].x)
Ltop--;
Lstack[++Ltop]=i;
/* int pos=Ltop,y;
for (int j=1<<18;j>0;j>>=1)
if (pos-j>0&&q[Lstack[pos-j]].x==q[i].x)
pos-=j;
y=q[Lstack[pos-1]].y+1;
pos=Rtop+1;
for (int j=1<<18;j>0;j>>=1)
if (pos-j>0&&q[Rstack[pos-j]].y>=y)
pos-=j;
ans+=Rtop-pos+1;*/
}
else {
q[i]=p[r++];
while (Rtop>0&&q[Rstack[Rtop]].x>q[i].x)
Rtop--;
Rstack[++Rtop]=i;
int pos=Rtop,y;
for (int j=1<<18;j>0;j>>=1)
if (pos-j>0&&q[Rstack[pos-j]].x==q[i].x)
pos-=j;
y=q[Rstack[pos-1]].y+1;
pos=Ltop+1;
for (int j=1<<18;j>0;j>>=1)
if (pos-j>0&&q[Lstack[pos-j]].y>=y)
pos-=j;
ans+=Ltop-pos+1;
}
for (int i=L;i<=R;i++)
p[i]=q[i];
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
p[i].get();
sort(p+1,p+n+1,cmpx);
solve(0,1e9,1,n);
printf("%lld\n",ans);
return 0;
}