Open Ural FU Championship 2013 G. Nested Segments(线段树&离散化)

G. Nested Segments

Time limit: 1.0 second
Memory limit: 64 MB
You are given  n segments on a straight line. For each pair of segments it is known that they either have no common points or all points of one segment belong to the second segment.
Then  m queries follow. Each query represents a point on the line. For each query, your task is to find the segment of the minimum length, to which this point belongs.

Input

The first line contains an integer  n that is the number of segments (1 ≤  n ≤ 10 5).  i’th of the next  n lines contains integers  a i and  b i that are the coordinates of endpoints of the  i’th segment (1 ≤  a i <  b i ≤ 10 9). The segments are ordered by non-decreasing  a i, and when  a i =  a j they are ordered by decreasing length. The next line contains an integer  m that is the number of queries (1 ≤  m ≤ 10 5).  j’th of the next  m lines contains an integer  c j that is the coordinate of the point (1 ≤  c j ≤ 10 9). The queries are ordered by non-decreasing  c j.

Output

For each query output the number of the corresponding segment on a single line. If the point does not belong to any segment, output “-1”. The segments are numbered from 1 to  n in order they are given in the input.

Sample

input output
3
2 10
2 3
5 7
11
1
2
3
4
5
6
7
8
9
10
11
-1
2
2
1
3
3
3
1
1
1
-1
Problem Author: Mikhail Rubinchik, idea by Nikita Pervukhin

To submit the solution for this problem go to the Problem set:  1987. Nested Segments

题意:

给你一些线段。然后得你一些点的坐标。问你找出包含该点的最短的一条线段。注意是标号而不是长度。。

思路:

开始以为长度结果看了半天。。。由于坐标的范围太大而线段的数目有限。所以要离散化。然后就是简单的线段树成段更新了。

详细见代码:

#include<algorithm>
#include<iostream>
#include<string.h>
#include<sstream>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<string>
#include<queue>
#include<set>
#include<map>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=100010;
int x[maxn<<2],y[maxn<<1],li[maxn],ri[maxn],len[maxn<<4],id[maxn<<4];
int ptr,cnt;
void btree(int L,int R,int k)
{
    int ls,rs,mid;
    ls=k<<1;
    rs=ls|1;
    mid=(L+R)>>1;
    len[k]=INF;//记录对应的最小长度
    id[k]=-1;//对应的线段标号
    if(L==R)
        return ;
    btree(L,mid,ls);
    btree(mid+1,R,rs);
}
void pushdown(int k)
{
    int ls,rs;
    ls=k<<1;
    rs=ls|1;
    if(len[ls]>len[k])
    {
        id[ls]=id[k];
        len[ls]=len[k];
    }
    if(len[rs]>len[k])
    {
        id[rs]=id[k];
        len[rs]=len[k];
    }
    len[k]=INF;
    id[k]=-1;
}
void update(int L,int R,int l,int r,int k,int d,int idd)
{
    int ls,rs,mid;
    if(l==L&&r==R)
    {
        if(len[k]>d)
        {
            len[k]=d;
            id[k]=idd;
        }
        return;
    }
    ls=k<<1;
    rs=ls|1;
    mid=(L+R)>>1;
    if(len[k]!=INF)
        pushdown(k);
    if(l>mid)
        update(mid+1,R,l,r,rs,d,idd);
    else if(r<=mid)
        update(L,mid,l,r,ls,d,idd);
    else
    {
        update(L,mid,l,mid,ls,d,idd);
        update(mid+1,R,mid+1,r,rs,d,idd);
    }
}
int binf(int p)//二分查找离散后的标号
{
    int mid,l,r;
    l=1,r=ptr-1;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(x[mid]==p)
            return mid;
        else if(p>x[mid])
            l=mid+1;
        else
            r=mid-1;
    }
    return -1;
}
int qu(int L,int R,int p,int k)
{
    int ls,rs,mid;
    if(L==R||len[k]!=INF)
        return id[k];
    ls=k<<1;
    rs=ls|1;
    mid=(L+R)>>1;
    if(p>mid)
        return qu(mid+1,R,p,rs);
    else
        return qu(L,mid,p,ls);
}
int binp(int p)//如果p不是端点值的话需二分查找
{
    int mid,l,r,ans=-1;
    l=1,r=cnt-1;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(y[mid]==p)
            return mid;
        else if(p>y[mid])
        {
            l=mid+1;
            ans=mid;
        }
        else
            r=mid-1;
    }
    if(ans!=-1)
        return binf(y[ans])+1;
    return -1;
}
int main()
{
    int i,l,r,n,m,p,ans,temp;

    while(~scanf("%d",&n))
    {
        ptr=cnt=1;
        for(i=1; i<=n; i++)
        {
            scanf("%d%d",&li[i],&ri[i]);
            x[ptr++]=li[i];
            x[ptr++]=ri[i];
        }
        sort(x,x+ptr);
        for(i=1;i<ptr;i++)
            y[cnt++]=x[i];
        temp=ptr;
        ptr=1;
        for(i=1; i<temp; i++)//离散化去重点
            if(x[i]!=x[i-1])
                x[ptr++]=x[i];
        for(i=ptr-1; i>1; i--)
            if(x[i]-x[i-1]>1)//离散化加中点
                x[ptr++]=x[i-1]+1;
        sort(x,x+ptr);
        btree(1,ptr,1);
        for(i=1;i<=n;i++)
        {
            l=binf(li[i]);
            r=binf(ri[i]);
            update(1,ptr,l,r,1,ri[i]-li[i]+1,i);
        }
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d",&p);
            if(p<x[1]||p>x[ptr-1])
                ans=-1;
            else
            {
                temp=binf(p);
                if(temp==-1)
                    p=binp(p);
                else
                    p=temp;
                if(p==-1)
                    ans=-1;
                else
                    ans=qu(1,ptr,p,1);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值