HDU 5107 线段树扫描线

使用线段树和扫描线解决高度查找问题
本文介绍了一种使用线段树和扫描线的方法来解决给定点集和高度集的情况下,在特定区域内查找第k小高度的问题。通过离散化Y坐标和对所有点及询问进行排序,实现高效查询。

给出N个点(x,y)。每一个点有一个高度h

给出M次询问。问在(x,y)范围内第k小的高度是多少,没有输出-1 (k<=10)

线段树扫描线


首先离散化Y坐标,以Y坐标建立线段树

对全部的点和询问进行离线操作,将询问和点依照x,y的大小排序,从左向右,从下向上。对于同样的(x,y)插入点在询问点之前

线段树的每一个节点维护10个高度,每次询问[0,mark[i].y]的第mark[i].h高的值就可以


#include "stdio.h"
#include "string.h"
#include "algorithm"
#include "map"
using namespace std;

map<int,int>mp;
struct Mark
{
    int x,y,h,op,id;
}mark[60010];
struct Ans
{
    int w; // 记录共同拥有多少个
    int h[11];
}ans;
struct node
{
    int l,r;
    Ans x;
}data[300010];
int y[60010],pri[30010];
bool cmp_mark(Mark a,Mark b)
{
    if (a.x!=b.x) return a.x<b.x;
    else
        if (a.y!=b.y) return a.y<b.y;
    else
        return a.op<b.op;
}

Ans Merge(Ans a,Ans b)
{
    int i,j,k;
    Ans c;
    i=j=k=1;
    while ((i<=a.w || j<=b.w) && k<=10)
    {
       if (j > b.w || (i <= a.w && a.h[i] < b.h[j]) )
            c.h[k++] = a.h[i++];
        else
            c.h[k++] = b.h[j++];
    }
    c.w=k-1;
    return c;
}

void build(int l,int r,int k)
{
    int mid;
    data[k].l=l;
    data[k].r=r;
    data[k].x.w=0;

    if(l==r) return ;

    mid=(l+r)/2;

    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
}

void updata(int n,int op,int k)
{
    int mid;
    if (data[k].l==n && data[k].r==n)
    {
        data[k].x.w++;
        data[k].x.h[data[k].x.w]=op;
        sort(data[k].x.h+1,data[k].x.h+1+data[k].x.w);
        return ;
    }

    mid=(data[k].l+data[k].r)/2;

    if (n<=mid) updata(n,op,k*2);
    else if (n>mid) updata(n,op,k*2+1);

    data[k].x=Merge(data[k*2].x,data[k*2+1].x);
}

Ans query(int l,int r,int k)
{
    int mid;
    if (data[k].l==l && data[k].r==r)
        return data[k].x;

    mid=(data[k].l+data[k].r)/2;

    if (r<=mid) return query(l,r,k*2);
    else
        if (l>mid) return query(l,r,k*2+1);
    else
        return Merge(query(l,mid,k*2),query(mid+1,r,k*2+1));
}
int main()
{
    int n,m,i,cnt,temp;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        for (i=0;i<n;i++)
        {
            scanf("%d%d%d",&mark[i].x,&mark[i].y,&mark[i].h);
            y[i]=mark[i].y;
            mark[i].op=1;
        }
        for (i=n;i<n+m;i++)
        {
            scanf("%d%d%d",&mark[i].x,&mark[i].y,&mark[i].h);
            mark[i].id=i-n;
            y[i]=mark[i].y;
            mark[i].op=2;
        }
        cnt=n+m;

        sort(y,y+cnt);
        sort(mark,mark+cnt,cmp_mark);

        temp=unique(y,y+cnt)-y; // 离散化

        for (i=0;i<temp;i++)
            mp[y[i]]=i;

        build(0,temp-1,1);

        for (i=0;i<cnt;i++)
        {
            if (mark[i].op==1)
                updata(mp[mark[i].y],mark[i].h,1);
            else
            {
                ans=query(0,mp[mark[i].y],1); // 询问返回该区间内前10个最小高度
                if (mark[i].h<=ans.w)
                pri[mark[i].id]=ans.h[mark[i].h];
                else
                    pri[mark[i].id]=-1;
            }
        }
        for (i=0;i<m;i++)
            printf("%d\n",pri[i]);
    }
    return 0;
}


乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值