1194E. Count The Rectangles(樹狀數組,離線掃描線)

1194E. Count The Rectangles(樹狀數組,離線掃描線)

題目鏈接:傳送門

思路:

首先看數據範圍,n5000n\le5000,我們首先處理出所有水平線段和垂直線段,然後將水平線段從低到高排序。

我們從低到高處理每條水平線段(計算出以該水平線段爲底的矩形的數量)。

假設現在是第 ii 條水平線段,首先我們O(n)O(n) 處理出所有與該線段相交的垂直線段,然後記錄與相交的垂直線段的最高點。我們現在維護這個最高點集合(用樹狀數組,用點的橫座標當下標,記錄某一橫座標範圍內點的數量)。

之後我們遍歷剩下的水平線段(比 ii 靠後的),假設現在遍歷的是第 j 條水平線段,那麼我們將集合中低於第 jj 條水平線段的點從集合中刪除,之後統計在第 jj 條線段橫座標範圍內的點的數量,這些點代表的垂直線段就與該兩條水平線段相交,假設有cnt個,那麼這兩條水平線段圍成的矩形就有cnt(cnt1)/2cnt*(cnt-1)/2個,我們遍歷完所有剩下的水平線段並向上面那樣維護就可以計算出所有以第 ii 條線段爲底的矩形的數量。

總的時間複雜度爲O(n2logn)O(n^2logn)

代碼:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int N=5e3+10;
const int MAXN=1e4+10;
struct HorizontalLine{
    int x1,x2,y;
    HorizontalLine(){}
    HorizontalLine(int y,int x1,int x2):y(y),x1(x1),x2(x2){}
    bool operator <(const HorizontalLine &o) const
    {
        return y<o.y;
    }
};
vector<HorizontalLine> hl;
struct VerticalLine{
    int x,y1,y2;
    VerticalLine(){}
    VerticalLine(int x,int y1,int y2):x(x),y1(y1),y2(y2){}
    bool operator < (const VerticalLine &o) const
    {
        return y2<o.y2;
    }
};
vector<VerticalLine> vl;
struct Point{
    int x,y;
    Point(){}
    Point(int x,int y):x(x),y(y){}
    bool operator < (const Point &o) const
    {
        return y<o.y;
    }
}po[N];
struct BITtree{
    int bt[N*2];
    int lowbit(int k)
    {
        return k&-k;
    }
    void add(int k,int val)
    {
        while(k<=MAXN)
        {
            bt[k]+=val;
            k+=lowbit(k);
        }
    }
    int getpre(int k)
    {
        int ans=0;
        while(k)
        {
            ans+=bt[k];
            k-=lowbit(k);
        }
        return ans;
    }
    int getlr(int l,int r)
    {
        return getpre(r)-getpre(l-1);
    }
}ooo;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        x1+=5001;
        x2+=5001;
        if(x1 > x2)
            swap(x1,x2);
        if(y1 > y2)
            swap(y1,y2);
        if(x1==x2)
        {
            vl.push_back(VerticalLine(x1,y1,y2));
        }
        else{
            hl.push_back(HorizontalLine(y1,x1,x2));
        }
    }
    sort(hl.begin(),hl.end());
    sort(vl.begin(),vl.end());
    long long ans=0;
    for(int i=0;i<int(hl.size());++i)
    {
        int y=hl[i].y,x1=hl[i].x1,x2=hl[i].x2;
        int top=0;
        for(int j=0;j<int(vl.size());++j)
        {
            if(vl[j].x<=x2&&vl[j].x>=x1&&vl[j].y1<=y&&vl[j].y2>=y)
            {
                po[top++]=Point(vl[j].x,vl[j].y2);
                ooo.add(vl[j].x,1);
            }
        }
        int p=0;//未添加的位置
        for(int j=i+1;j<int(hl.size());++j)
        {
            while(p<top&&po[p].y<hl[j].y)
            {
                ooo.add(po[p].x,-1);
                ++p;
            }
            int cnt=ooo.getlr(hl[j].x1,hl[j].x2);
            ans+=1ll*cnt*(cnt-1)/2;
        }
        while(p<top)
        {
            ooo.add(po[p].x,-1);
            ++p;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章