HDU 5862 Counting Intersections(樹狀陣列+掃描線+離散化)

Mr_Treeeee發表於2020-04-06

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);
    }

}



相關文章