hdu5862 Counting Intersections

/*
    题目描述:给出n(0 < n <= 1e5)条水平或竖直的线段,且同一方向上的线段不存在重合,问这些线段一共有多少交点
    
    方法:将水平线段存在vy中,竖直线段存在vx中,将vx、vy按照先左后右、先下后上的顺序排序,然后对y方向的坐标
        进行离散化。然后从左向右依次取出一条竖直的线段,计算每一条竖直线段与水平线段交点的个数,将他们相加就
        是答案,具体方法如下:
                    用一个树状数组维护每个y高度存在的线段的个数,这样可以在logn的时间内统计出从y1到y2高度中的水平线段
            有多少。假设当前拿出来的竖直线段为(x0 , r , x0 , s),首先找到所有满足x1 <= x0 <= x2的水平线段(x1 , y0 , x2 , y0),
            然后将y0在树状数组中加一,然后树状数组查询一次得交点个数;然后再拿出下一条竖直线段(x0' , k , x0' , t),先将刚才
            在树状数组中做过标记的水平线段中不满足x1 <= x0' <= x2的线段对应的y0位置减一,然后再将新的满足条件的水平
            线段加进来,然后求这条竖直线段与水平线段的交点个数;依此类推求第三条第四条第五条等等的竖直线段交点数
                    判断x1 <= x0 <= x2的方法见代码
*/
#pragma warning(disable:4786)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-8;
struct node
{
    int x1 , y1 , x2 , y2;
    bool operator < (const node & rhs)const{
        return x2 > rhs.x2;
    }
};
bool cmp(const node a , const node b)
{
    if(a.x1 < b.x1)
        return true;
    else if(a.x1 == b.x1)
        return a.y1 < b.y1;
    else
        return false;
}
vector< node >vx;
vector< node >vy;
vector< int >v;
map<int , int>mp;
int n , num1 , num2 , cnt1 , cnt2;
int c[300000];
priority_queue<node>Q;
int lowbit(int x)
{
    return x & (-x);
}
void modify(int x , int val)
{
    while(x <= cnt2){
        c[x] += val;
        x += lowbit(x);
    }
}
LL sum(int x)
{
    LL res = 0;
    while(x > 0){
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}
void init()
{
    mem(c , 0);
    v.clear();
    vx.clear();     vy.clear();
    mp.clear();
    while(!Q.empty())
        Q.pop();
}
void read()
{
        int x1 , y1 , x2 , y2;
        node st;
        scanf("%d",&n);
        for(int i = 0 ; i<n ;i++){
            scanf("%d %d %d %d",&x1 , &y1 , &x2 , &y2);
            if(x1 == x2){
                st.x1 = x1 ;    st.x2 = x2;
                if(y1 > y2){
                    swap(y1 , y2);
                }
                st.y1 = y1;     st.y2 = y2;
                vy.push_back(st);
                v.push_back(y1);   v.push_back(y2);
            }
            else{
                st.y1 = y1;     st.y2 = y2;
                if(x1 > x2){
                    swap(x1 , x2);
                }
                st.x1 = x1;     st.x2 = x2;
                vx.push_back(st);
                v.push_back(y1);
            }
        }
}
void discretization()
{
        sort(v.begin() , v.end());
        cnt2 = unique(v.begin() , v.end() ) - v.begin();
        for(int i = 0 ; i<cnt2 ; i++){
            mp[v[i]] = i + 1;
        }
        for(int i = 0 ; i < vx.size() ; i++){
            vx[i].y1 = mp[vx[i].y1];
            vx[i].y2 = mp[vx[i].y2];
        }
        for(int i = 0 ; i < vy.size() ; i++){
            vy[i].y1 = mp[vy[i].y1];
            vy[i].y2 = mp[vy[i].y2];
        }
        sort(vx.begin() , vx.end() , cmp);
        sort(vy.begin() , vy.end() , cmp);
}
int main()
{
    int T ;
    scanf("%d", &T);
    while(T--){
        init();
        read();
        discretization();
        node st , cur;
        int i , j = 0;
        num1 = vy.size();
        num2 = vx.size();
        LL ans = 0;
        for(i = 0 ; i < num1 ; i++){
            st = vy[i];
            for(;j < num2; j++){
                if(vx[j].x1 <= st.x1){      //将左端点小于等于当前竖直线段x坐标的线段入队并对其y坐标进行标记
                    Q.push(vx[j]);
                    modify(vx[j].y1 , 1);
                }
                else    break;
            }
            while(!Q.empty()){      //将队列中右端点小于当前竖直线段x坐标的线段出队并取消对其y坐标标记
                cur = Q.top();
                if(cur.x2 >= st.x1)     break;  
                else{
                    Q.pop();
                    modify(cur.y1 , -1);
                }
            }
            ans += sum(st.y2) - sum(st.y1 - 1);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值