由于题目描述过于沙雕,这里给出题目大意:
在坐标系内有
n
n
n个点。如果一对点
x
x
x和
y
y
y是合法的,满足一个边平行于坐标轴的矩形仅包含这两个点,求合法点对数。
n
<
=
1
0
5
n<=10^5
n<=105
分析:
这题和bzoj 4237:稻草人是一个道理。
有几个注意的地方,首先还要计算上朝下的,而且在直线上相邻的两个点也有贡献。
因为这题不保证
x
i
x_i
xi和
y
i
y_i
yi两两不同,要特判重点以及按
y
y
y排序时还要以
x
x
x为第二关键字从大到小排序,因为
y
y
y相同时,
x
x
x比较小点可以覆盖掉
x
x
x比较大的点。
判重点可以一开始就统计答案,然后不讨论这个点对别的点的贡献。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define LL long long
const int maxn=1e5+7;
const int inf=1e9;
using namespace std;
int n,cnt,top,tot;
int lastu[maxn],lastd[maxn],sta[maxn],q[maxn];
LL ans;
struct point{
int x,y;
}a[maxn];
struct rec{
int x,y,k,op;
}b[maxn];
bool cmp(point a,point b)
{
if (a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmp1(rec a,rec b)
{
if (a.y==b.y) return a.x>b.x;
return a.y>b.y;
}
bool cmp2(rec a,rec b)
{
if (a.y==b.y) return a.x>b.x;
return a.y<b.y;
}
int findd(int x)
{
int l=1,r=top,ans=0;
while (a[sta[l]].x==a[x].x) l++;
while (l<=r)
{
int mid=(l+r)/2;
if (a[sta[mid]].y<lastd[x]) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int findu(int x)
{
int l=1,r=top,ans=0;
while (l<=r)
{
int mid=(l+r)/2;
if (a[sta[mid]].y>lastu[x]) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
void cdq(int l,int r,int ql,int qr)
{
if (ql==qr) return;
int midq=(ql+qr)/2;
cdq(q[ql],q[midq+1]-1,ql,midq);
cdq(q[midq+1],q[qr+1]-1,midq+1,qr);
int mid=q[midq+1]-1;
cnt=top=0;
for (int i=l;i<=r;i++) b[++cnt]=(rec){a[i].x,a[i].y,i,(i>mid)};
sort(b+1,b+cnt+1,cmp1);
for (int i=1;i<=cnt;i++)
{
if (b[i].op==0)
{
if ((a[sta[top]].y<lastd[b[i].k]) && (top))
{
int d=findd(b[i].k);
ans+=(LL)top-(LL)d+1;
lastd[b[i].k]=a[sta[top]].y;
}
}
else
{
if ((top) && (a[sta[top]].x==a[b[i].k].x) && (a[sta[top]].y==a[b[i].k].y))
{
top--;
continue;
}
while ((top) && (a[sta[top]].x>=a[b[i].k].x)) top--;
sta[++top]=b[i].k;
}
}
top=0;
sort(b+1,b+cnt+1,cmp2);
for (int i=1;i<=cnt;i++)
{
if (b[i].op==0)
{
if ((a[sta[top]].y>lastu[b[i].k]) && (top))
{
int d=findu(b[i].k);
ans+=(LL)top-(LL)d+1;
lastu[b[i].k]=a[sta[top]].y;
if (lastu[b[i].k]==lastd[b[i].k]) ans--;
}
}
else
{
if ((top) && (a[sta[top]].x==a[b[i].k].x) && (a[sta[top]].y==a[b[i].k].y))
{
top--;
continue;
}
while ((top) && (a[sta[top]].x>=a[b[i].k].x)) top--;
sta[++top]=b[i].k;
}
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;i++)
{
lastu[i]=-inf;
lastd[i]=inf;
}
tot=1;
q[tot]=1;
for (int i=2;i<=n;i++)
{
if (a[i].x==a[i-1].x)
{
ans++;
lastu[i]=max(lastu[i],a[i-1].y);
lastd[i-1]=min(lastd[i-1],a[i].y);
if (a[i].y==a[i-1].y)
{
lastd[i]=min(lastd[i],a[i].y);
lastu[i-1]=max(lastu[i-1],a[i].y);
}
}
else q[++tot]=i;
}
q[tot+1]=n+1;
cdq(1,n,1,tot);
printf("%lld",ans);
}