我是靠谱客的博主 快乐缘分,最近开发中收集的这篇文章主要介绍HDU 6681(树状数组统计平面内射线的交点个数)HDU 6681(树状数组,统计平面内射线的交点个数),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

HDU 6681(树状数组,统计平面内射线的交点个数)

题目链接:传送门

题意:给出k条射线,求射线将 n ∗ m n*m nm 的区域分成几个联通块。每两条射线的端点x坐标和y坐标都互不相同。

思路:根据 欧拉公式 可以推导出联通块的个数等于射线的焦点个数c+1。但其实赛场上根本不知道这个定理,但有个很明显的道理,对于每条竖线,每条横着的射线与该竖线相交都会使联通块个数+1.(注意因为题目限制,这个射线的端点不会在边界上,不然在边界的射线会使联通块+2)。所以我们直接统计出射线的交点个数即可,这是个经典问题(但是我当时不会

​ 其实对于每条竖着的射线(假设端点为 x 0 , y 0 ​ x0,y0​ x0,y0),只要能统计出它左边横着的射线与之相交的射线个数和,即相交的射线的端点 x , y ​ x,y​ x,y满足射线方向向右且 x &lt; x 0 ​ x&lt;x0​ x<x0,y在射线( x 0 , y 0 ​ x0,y0​ x0,y0)纵坐标覆盖范围之内即可。统计左边横着的射线与之相交的射线个数也是同样道理

​ 因为射线的个数 k k k的范围为 1 e 5 ​ 1e5​ 1e5,故使用二维前缀和肯定是不行的。

​ 我们可以分类统计,我们先来统计每条射线左边横着的射线与之相交的射线个数,我们可以先将所有竖直方向的射线按 x x x从小到大排序,所有横着的射线按 x x x从小到大排序,对于第 i i i 条竖直方向的射线,我们可以处理所有左边的横着向右的射线,然后把他们的 y y y坐标加入树状数组 (这里需要对 y y y坐标进行离散化)。然后可以 O ( l o g n ) O(logn) O(logn)统计出树状数组内 y y y在第一条射线纵坐标覆盖范围之内的点的个数。双指针优化后可达到O(n)统计的效果。

欧拉公式:欧拉公式介绍

代码:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long u64;
typedef pair<int,int> P;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
const int L=0,R=1,U=2,D=3;
ll X[N],Y[N],kinds[N],n,m,K,pes[N];
ll bt[N];
ll maxm;
struct node
{
    ll x,y,kind;
    node() {}
    node(ll x,ll y,ll kind):x(x),y(y),kind(kind) {}


    bool operator <(const node& other) const
    {
        return x<other.x;
    }
};
vector<node> row,col;
void disperse(ll X[],ll n)
{
    ll cnt=0;
    for(ll i=1; i<=n; ++i)
        pes[cnt++]=X[i];
    sort(pes,pes+cnt);
    cnt=unique(pes,pes+cnt)-pes;
    for(ll i=1; i<=n; ++i)
    {
        X[i]=lower_bound(pes,pes+cnt,X[i])-pes+1;
    }
}
ll lowbit(ll k)
{
    return k&-k;
}
void add(ll k,ll val)
{
    while(k<=maxm)
    {
        bt[k]+=val;
        k+=lowbit(k);
    }
}
ll get(ll k)
{
    ll ans=0;
    while(k)
    {
        ans+=bt[k];
        k-=lowbit(k);
    }
    return ans;
}
ll calc(ll l,ll r)
{
    return get(r)-get(l-1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    ll t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m>>K;
        for(ll i=1; i<=K; ++i)
        {
            char c;
            cin>>X[i]>>Y[i]>>c;
            switch (c)
            {
            case 'L':
                kinds[i]=L;
                break;
            case 'R':
                kinds[i]=R;
                break;
            case 'U':
                kinds[i]=U;
                break;
            case 'D':
                kinds[i]=D;
                break;
            }
        }
        Y[K+1]=m;
        //离散化
        disperse(Y,K+1);
        maxm=Y[K+1];
        row.clear(),col.clear();
        //加入行列数组
        for(ll i=1; i<=K; ++i)
        {
            if(kinds[i]==L||kinds[i]==R)
            {
                row.push_back({X[i],Y[i],kinds[i]});
            }
            else
            {
                col.push_back({X[i],Y[i],kinds[i]});
            }
        }
        sort(row.begin(),row.end());
        sort(col.begin(),col.end());
        mset(bt,0);
        int p=0;
        ll ans=0;
        //进行双指针并树状数组维护信息
        /*统计每条竖线与左侧射线的交点个数*/
        for(ll i=0ll; i<col.size(); ++i)
        {
            ll x=col[i].x,y=col[i].y;
            while(p<row.size()&&row[p].x<x)
            {
                if(row[p].kind==R)
                    add(row[p].y,1);
                ++p;
            }
            if(col[i].kind==U)
                ans+=calc(y,maxm);
            else
                ans+=calc(1,y);
        }
        /*统计每条竖线与右侧射线的交点个数*/
        mset(bt,0);
        p=row.size()-1;
        for(ll i=col.size()-1ll; ~i; --i)
        {

            ll x=col[i].x,y=col[i].y;
            while(p>=0&&row[p].x>x)
            {
                if(row[p].kind==L)
                    add(row[p].y,1);
                --p;
            }

            if(col[i].kind==U)
                ans+=calc(y,maxm);
            else
                ans+=calc(1,y);
        }
        cout<<ans+1<<endl;
    }
    return 0;
}

最后

以上就是快乐缘分为你收集整理的HDU 6681(树状数组统计平面内射线的交点个数)HDU 6681(树状数组,统计平面内射线的交点个数)的全部内容,希望文章能够帮你解决HDU 6681(树状数组统计平面内射线的交点个数)HDU 6681(树状数组,统计平面内射线的交点个数)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部