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

G. Nested Segments

Time limit: 1.0 second
Memory limit: 64 MB
You are given nsegments 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 mqueries 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 nthat is the number of segments (1 ≤ n≤ 10 5). i’th of the next nlines contains integers a iand b ithat 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 jthey are ordered by decreasing length. The next line contains an integer mthat is the number of queries (1 ≤ m≤ 10 5). j’th of the next mlines contains an integer c jthat is the coordinate of the point (1 ≤ c j≤ 10 9). Thequeries 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 nin 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:<nobr style="font-family:Simsun; font-size:14px"><a target="_blank" href="http://acm.timus.ru/problem.aspx?space=1&amp;num=1987" style="font-family:Simsun; font-size:14px">1987. Nested Segments</a></nobr>

题意:

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

思路:

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

详细见代码:

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值