codeforces educational round 68 E - Count The Rectangles

 这个代码不太好写,应该是我的方法丑了吧。

我的思路是将答案按照下边界所属的线段进行分类。

首先,我们提取出所有的横线,并按照y值排序。对于每一条横线 p,我们从小到大枚举y值大于他的横线 q(类似于扫描线的思想)。并用线段树维护对于当前的横线q,竖线的下端点纵坐标小于横线p的纵坐标,并且上端点的y值大于等于横线q的y值的竖线的x值。然后答案的统计就是查询两条横线相交的区间内竖线的个数 x 。那么他对答案的贡献为 C(x,2).

反思:最大的收获就是用lowerbound进行查找满足某一条件的区间,严格根据定义来是不会Re的,这次我考虑清楚了。

坑点:我最开始再第50组样例 Re了,原因是对空的vector进行lower_bound 会导致RE。

#include <bits/stdc++.h>
#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<Line> 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<lint> 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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值