题目描述
题解
对x排序了之后按照x分治,每一次对y排序
考虑如何处理左区间里的点对右边的点的影响,也就是如何计算左边和右边配对的情况
用两个指针扫的时候,如果左边的连续一段区间里的点想要都和右边的某一个点配对的话,必须满足x单调递减
而右边的区间的某一个点如果要是想和左边的点配对的话,只能是y在 它和第一个x在它左边的点 所确定的y的范围内的点
对于左边的点维护一个x单调递减的栈,对右边的点维护一个x单调递增的栈,然后对于每一个右边的点,在左边查询栈中y在它和它前一个点的y的范围内的点
画个图理解一下…
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 200005
#define LL long long
int n,topl,topr,sl[N],sr[N];
struct data{int x,y;}q[N],p[N];
LL ans;
int cmp(data a,data b)
{
return a.x<b.x;
}
void pushl(int id)
{
while (topl&&q[id].x>q[sl[topl]].x)
--topl;
sl[++topl]=id;
}
void pushr(int id)
{
while (topr&&q[id].x<q[sr[topr]].x)
--topr;
sr[++topr]=id;
}
int find(int id)
{
if (!id) return topl;
int l=1,r=topl,mid,ans=0;
while (l<=r)
{
mid=(l+r)>>1;
if (q[sl[mid]].y>q[id].y) ans=topl-mid+1,r=mid-1;
else l=mid+1;
}
return ans;
}
void cdq(int l,int r)
{
if (l>=r) return;
int mid=(l+r)>>1;
cdq(l,mid);
cdq(mid+1,r);
topl=topr=0;
int pl=l,pr=mid+1;
while (pr<=r)
{
pushr(pr);
while (pl<=mid&&q[pl].y<q[pr].y)
{
pushl(pl);
++pl;
}
ans+=(LL)find(sr[topr-1]);
++pr;
}
int ll=l,rr=mid+1,now=l;
while (ll<=mid&&rr<=r)
{
if (q[ll].y<q[rr].y) p[now++]=q[ll++];
else p[now++]=q[rr++];
}
while (ll<=mid) p[now++]=q[ll++];
while (rr<=r) p[now++]=q[rr++];
for (int i=l;i<=r;++i) q[i]=p[i];
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d%d",&q[i].x,&q[i].y);
sort(q+1,q+n+1,cmp);
cdq(1,n);
printf("%lld\n",ans);
}