G. Nested Segments
Time limit: 1.0 second
Memory limit: 64 MB
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&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;
}