BZOJ4237 稻草人 分治 单调栈
原文链接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; }