链接:BZOJ1818
解法:树状数组
题意转化为求线段的交点个数。
先将任一坐标离散化,这里以
x
x
为例。之后将 与
y
y
坐标分别排序,求出这些线段。以样例为例,如下图:( 坐标已离散化,只有在同一横/纵坐标上出现多个点时才会出现线段。)
将线段分两种,横与竖。
将横线段拆为两个点,竖线段不变。然后将这些东西排序。从左至右扫描(若是离散化
y
y
坐标则从下至上),扫描到横线段的左端点时,将该横线段的横坐标处的位置 ,扫描到横线段的右端点则
−1
−
1
;扫描到竖线段则查询线段的上下端点,加入答案。区间查询用树状数组维护即可。
细节很多,实现时心态很容易崩(
cmp
c
m
p
函数别打错)
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
struct data{
int x,y,i;
data():x(0),y(0),i(0){}
data(int a,int b,int j):x(a),y(b),i(j){}
};
struct upd{
int t,x,l,r;
upd(){}
upd(int u,int y,int a,int b):t(u),x(y),l(a),r(b){}
friend bool operator<(const upd &u1,const upd &u2){if(u1.x==u2.x)return u1.t<u2.t;else return u1.x<u2.x;}
};
int n,rnk[100002],sum[100002];
long long ans;
data dt[100002];
vector<upd> V;
inline bool cmp1(const data &dt1,const data &dt2){if(dt1.x==dt2.x)return dt1.y<dt2.y;return dt1.x<dt2.x;}
inline bool cmp2(const data &dt1,const data &dt2){if(dt1.y==dt2.y)return dt1.x<dt2.x;return dt1.y<dt2.y;}
inline int lowbit(int x){return x&-x;}
void update(int k,int x){for(int i=k;i<=n;i+=lowbit(i))sum[i]+=x;}
int query(int k){int res=0;for(int i=k;i>0;i-=lowbit(i))res+=sum[i];return res;}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d%d",&dt[i].x,&dt[i].y),dt[i].i=i;
sort(dt+1,dt+n+1,cmp1);
dt[0].x=2147483647;for(int i=1,j=0;i<=n;++i)if(dt[i].x==dt[i-1].x)rnk[dt[i].i]=j;else rnk[dt[i].i]=++j;
sort(dt+1,dt+n+1,cmp2);
for(int i=1;i<=n;++i){int j=i;if(dt[j+1].y==dt[j].y)++j;if(i!=j)V.push_back(upd(1,dt[i].y,rnk[dt[i].i],rnk[dt[j].i]));}
sort(dt+1,dt+n+1,cmp1);
for(int i=1;i<=n;++i){int j=i;if(rnk[dt[j+1].i]==rnk[dt[j].i])++j;if(i!=j)V.push_back(upd(2,dt[i].y,rnk[dt[i].i],1)),V.push_back(upd(2,dt[j].y,rnk[dt[j].i],-1));}
sort(V.begin(),V.end());
for(upd u:V)if(u.t==2)update(u.l,u.r);else ans+=query(u.r-1)-query(u.l);
printf("%lld",ans+n);
}