总的来说就是将x标记然后一条条y扫描并用树状数组处理
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=200000+100;
struct node
{
int x;
int y;
}p[maxn];
int a[maxn];
int b[maxn];
int n,cur;
bool vis[maxn],l[maxn],r[maxn];
bool cmp(node u,node v)
{
if(u.y==v.y)
return u.x<v.x;
return u.y<v.y;
}
int low(int k)
{
return k&(-k);
}
void update(int k,int v)
{
while(k<maxn)
{
a[k]+=v;
k+=low(k);
}
}
long long sum(int k)
{
long long ans=0;
while(k>0)
{
ans+=a[k];
k-=low(k);
}
return ans;
}
void init()//预处理
{
memset(a,0,sizeof(a));//初始化树状数组
sort(b,b+cur);
cur=unique(b,b+cur)-b;//排序,离散化 //b-重复元素
//cout<<cur<<endl;
for(int i=0;i<n;i++)
{
p[i].x=lower_bound(b,b+cur,p[i].x)-b+1;
p[i].y=lower_bound(b,b+cur,p[i].y)-b+1;
//cout<<i<<" "<<p[i].x<<" "<<p[i].y<<endl;
}
sort(p,p+n,cmp);//按y排序,已y坐标建扫描线 y从小到大排序
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
if(!vis[p[i].x])//预处理,k位置在下方第一次出现
{
l[i]=1;
vis[p[i].x]=1;
}
else
l[i]=0;
}
memset(vis,0,sizeof(vis));
for(int i=n-1;i>=0;i--)
{
if(!vis[p[i].x])//第k个点的x坐标在上方出现第一次出现
{
r[i]=1;
vis[p[i].x]=1;
}
else
r[i]=0;
}
}
void solve()
{
long long ans=0;
for(int i=0;i<n;)
{
cout<<i<<" "<<ans<<endl;
int j=i;
while(j<n-1&&p[j].y==p[j+1].y)//同一条扫描线
j++;
for(int k=i;k<=j;k++)
{
if(!l[k]&&r[k])// 最上面的点,且下面存在被染色的点
{
update(p[k].x,-1);
}
}
if(i!=j)
ans+=(sum(p[j].x-1)-sum(p[i].x));//p[j].x-1到p[i].x间被改变颜色的点
if(i<j)
{
for(int k=i+1;k<j;k++)
if(!l[k]&&!r[k])//原来是黑色的点
ans--;
}
while(i<=j)
{
if(l[i]&&!r[i])//p[i].x是最底下的位置,且上面有元素,p[i].x上的要被染色
update(p[i].x,1);
i++;
}
}
printf("%I64d\n",ans+n);
}
int main()
{
while(~scanf("%d",&n))
{
cur=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&p[i].x,&p[i].y);
b[cur++]=p[i].x;
b[cur++]=p[i].y;
}
//for(int i = 0;i<n*2;++i){
//cout<<b[i]<<endl;
//}
init(); //左右x第一次出现
solve(); //
}
return 0;
}