链接: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);
}