这个代码不太好写,应该是我的方法丑了吧。
我的思路是将答案按照下边界所属的线段进行分类。
首先,我们提取出所有的横线,并按照y值排序。对于每一条横线 p,我们从小到大枚举y值大于他的横线 q(类似于扫描线的思想)。并用线段树维护对于当前的横线q,竖线的下端点纵坐标小于横线p的纵坐标,并且上端点的y值大于等于横线q的y值的竖线的x值。然后答案的统计就是查询两条横线相交的区间内竖线的个数 x 。那么他对答案的贡献为 C(x,2).
反思:最大的收获就是用lowerbound进行查找满足某一条件的区间,严格根据定义来是不会Re的,这次我考虑清楚了。
坑点:我最开始再第50组样例 Re了,原因是对空的vector进行lower_bound 会导致RE。
#include
#define lc l,mid,x<<1
#define rc mid+1,r,x<<1|1
using namespace std;
typedef int lint;
typedef long long LL;
const lint maxn = 20005;
struct Line{
lint x1,y1,x2,y2;
Line( lint xx1 = 0,lint yy1 = 0,lint xx2 = 0,lint yy2 = 0 ){
x1 =xx1;y1=yy1;x2=xx2;y2=yy2;
}
};
vector vey,vebegin,veend;
bool cmpy( const Line& a,const Line& b ){
return a.y1 < b.y1;
}
bool cmpbegin( const Line& a,const Line& b ){
return a.y1 < b.y1;
}
bool cmpend( const Line& a,const Line& b ){
return a.y2 < b.y2;
}
LL ans = 0;
lint tree[6*maxn];
void push_up( lint x ){
tree[x]=tree[x<<1]+tree[x<<1|1];
}
void update( lint left,lint right,lint v,lint l,lint r,lint x ){
if( left <= l && right >= r ){
tree[x] += v;
return;
}
lint mid = l + r >> 1;
if( left <= mid ){
update( left,right,v,lc );
}
if( right > mid ){
update( left,right,v,rc );
}
push_up(x);
}
lint ask( lint left,lint right,lint l,lint r,lint x ){
if( left <= l && right >= r ){
return tree[x];
}
lint mid = l+r>>1;
lint res = 0;
if( left <= mid ){
res += ask( left,right,lc );
}
if( right > mid ){
res += ask( left,right,rc );
}
return res;
}
vector ve;
lint flag[maxn];
LL cal( lint x,lint y ){
lint yx = vey[x].y1,yy = vey[y].y1;
lint p1;
if( flag[x] ) p1 = lower_bound( veend.begin(),veend.end(),vey[y-1],cmpend ) -veend.begin() ;
else p1 = upper_bound( veend.begin(),veend.end(),vey[y-1],cmpend ) -veend.begin() ;
lint p2 = lower_bound( veend.begin(),veend.end(),vey[y],cmpend )-veend.begin()-1;
if( yy != yx ) flag[x]=1;
for( lint i = p1;i <= p2;i++ ){
Line cur = veend[i];
if( cur.y1 <= yx ){
update( cur.x1,cur.x1,-1,0,10000,1 );
ve.push_back(cur.x1);
}
}
if( yx == yy ) return 0;
lint left = max( vey[x].x1,vey[y].x1 );
lint right = min( vey[x].x2,vey[y].x2 );
if( left >= right ) return 0;
lint cnt = ask( left,right,0,10000,1 );
return (LL)cnt*(cnt-1)/2;
}
void solve(){
for( lint i = 0;i < vey.size()-1;i++ ){
for( lint j = i+1;j < vey.size();j++ ){
ans += cal( i,j );
}
for( lint k = 0;k < ve.size();k++ ){
update( ve[k],ve[k],1,0,10000,1 );
}
ve.clear();
lint p1 = upper_bound( veend.begin(),veend.end(),vey[i] ,cmpend ) -veend.begin() ;
lint p2 = upper_bound( veend.begin(),veend.end(),vey[i+1] ,cmpend )-veend.begin()-1;
for( lint j = p1;j<= p2;j++ ){
update( veend[j].x1,veend[j].x1,-1,0,10000,1 );
}
p1 = upper_bound( vebegin.begin(),vebegin.end(),vey[i],cmpbegin ) -vebegin.begin() ;
p2 = upper_bound( vebegin.begin(),vebegin.end(),vey[i+1],cmpbegin )-vebegin.begin()-1;
for( lint j = p1;j<= p2;j++ ){
update( vebegin[j].x1,vebegin[j].x1,1,0,10000,1 );
}
}
}
void prework(){
lint p1 = upper_bound( vebegin.begin(),vebegin.end(),vey[0],cmpbegin ) - vebegin.begin()-1;
lint p2 = upper_bound( veend.begin(),veend.end(),vey[0],cmpend )-veend.begin()-1;
for( lint i = 0;i <= p1;i++ ){
Line cur = vebegin[i];
update( cur.x1,cur.x1,1,0,10000,1 );
}
for( lint i = 0;i <= p2;i++ ){
Line cur = veend[i];
update( cur.x1,cur.x1,-1,0,10000,1 );
}
}
int main(){
lint n,x1,y1,x2,y2;
scanf("%d",&n);
for( int i = 1;i <= n;i++ ){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1 += 5000;x2 += 5000;
if( y1 == y2 ){
if( x1 > x2 ) swap( x1,x2 );
vey.push_back( Line( x1,y1,x2,y2 ) );
}else{
if( y1 > y2 ) swap(y1,y2);
vebegin.push_back( Line( x1,y1,x2,y2 ) );
veend.push_back( Line( x1,y1,x2,y2 ) );
}
}
if( vey.size() == 0 ){
cout << 0 << endl;
return 0;
}
sort( vey.begin(),vey.end(),cmpy );
sort( vebegin.begin(),vebegin.end(),cmpbegin );
sort( veend.begin(),veend.end(),cmpend );
prework();
solve();
cout << ans << endl;
return 0;
}