HDU 5862 Counting Intersections(树状数组+扫描线+离散化)

Counting Intersections

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1296    Accepted Submission(s): 407


Problem Description
Given some segments which are paralleled to the coordinate axis. You need to count the number of their intersection.

The input data guarantee that no two segments share the same endpoint, no covered segments, and no segments with length 0.
 

Input
The first line contains an integer T, indicates the number of test case.

The first line of each test case contains a number n(1<=n<=100000), the number of segments. Next n lines, each with for integers, x1, y1, x2, y2, means the two endpoints of a segment. The absolute value of the coordinate is no larger than 1e9.
 

Output
For each test case, output one line, the number of intersection.
 

Sample Input
  
  
2 4 1 0 1 3 2 0 2 3 0 1 3 1 0 2 3 2 4 0 0 2 0 3 0 3 2 3 3 1 3 0 3 0 2
 

Sample Output
  
  
4 0
 

Author
BUPT
 

Source
 

题意:

给你几根与坐标轴平行的线,问你产生几个交点。

POINT:

树状数组的区间值是保存了y区间内有几根横线。

把y轴离散化。横线只要看成2个点,和竖线一起依x轴从小到大排序。

然后从左向右扫描,扫描到左端点,就y点+1,右端点就-1,扫描到竖线,就查询竖线上的y区间内右几根横线。(单点修改,区间查询)

注意端点与线重合的情况,优先扫描左端点,然后再扫描竖线,最后是右端点,不然答案会少。画一个右端点和竖线重合的图思考一下。

(就是为了去补这题多校,才去做了很多线段树和树状数组,终于把这题1A了,思考时间也不长,写的很快还没有错,那么线段树和树状数组也就告一段落,下面学习RMQ吧。自己还有很多要学的呢。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N = 100050*5;
#define  LL long long
struct node//离散纵坐标
{
    int x,y1,y2;
    int flag;//零代表竖线, 1代表横线左端点 -1右端点
}dian[N];
int haha[N];
int mm;
int yy[N];
int num[N];
int lowbit(int x)
{
    return x&-x;
}
void add(int x,int c)
{
    while(x<=mm)
    {
        num[x]+=c;
        x+=lowbit(x);
    }
}
LL query(int x)
{
    LL ans=0;
    while(x>=1)
    {
        ans+=(LL)num[x];
        x-=lowbit(x);
    }
    return ans;
}
int Discretization(int y)
{
    return (int)(lower_bound(yy+1,yy+1+mm,y)-yy);
}
bool cmd(node a,node b)
{
    if(a.x!=b.x)
        return a.x<b.x;
    else
        return a.flag>b.flag;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        memset(dian,0,sizeof dian);
        memset(haha,0,sizeof haha);
        memset(yy,0,sizeof yy);
        memset(num,0,sizeof num);
        int m=0;
        int my=0;
        for(int i=1;i<=n;i++)
        {
            int x1,x2,y1,y2;
            scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            if(x1>x2) swap(x1,x2);
            if(y1>y2) swap(y1,y2);
            if(x1==x2)
            {
                dian[++m].x=x1;
                dian[m].flag=0,dian[m].y1=y1,dian[m].y2=y2;
                yy[++my]=y1;
                yy[++my]=y2;
            }
            else
            {
                dian[++m].x=x1;
                dian[m].flag=1,dian[m].y1=dian[m].y2=y1;
                dian[++m].x=x2;
                dian[m].flag=-1,dian[m].y1=dian[m].y2=y2;
                yy[++my]=y1;
            }
        }
        sort(yy+1,yy+1+my);
        mm=1;
        for(int i=2;i<=my;i++)
        {
            if(yy[i-1]!=yy[i]) yy[++mm]=yy[i];
        }
        sort(dian+1,dian+1+m,cmd);
        LL ans=0;
        for(int i=1;i<=m;i++)
        {
            if(dian[i].flag==0)//竖线
            {
                int Y=Discretization(dian[i].y2);
                int y=Discretization(dian[i].y1);
                ans+=query(Y)-query(y-1);
            }
            else if(dian[i].flag==-1)//右端点
            {
                int y=Discretization(dian[i].y1);
                add(y,-1);
            }
            else
            {
                int y=Discretization(dian[i].y1);
                add(y,1);
            }
        }
        printf("%lld\n",ans);
    }

}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值