URAL1987. Nested Segments 线段树

1987. 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 ≤ 105). i’th of the
next n lines contains integers ai and bi that are the
coordinates of endpoints of the i’th segment (1 ≤ ai < bi ≤
109). The segments are ordered by non-decreasing ai, and when ai = aj they
are ordered by decreasing length. All segments are distinct. The next line contains an integer m that is the number of queries (1 ≤ m ≤ 105). j’th of the
next m lines contains an integer cj that is the coordinate of the point (1 ≤ cj ≤
109). The queries are ordered by non-decreasing cj.

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

题意:

有n个段,编号1-n,每个段占据着a-b。 m个查询,查询c处所在的段中,长度最短的是几号段。如果没有段占据,输出-1。

首先把所有数字存在数组里,去离散化。然后把id按段的长度从长到短更新到树中。然后就查询固定的点在树中的ID的就行了。

#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL int
const int maxn = 811111;
LL ID[maxn<<2];//记录该点属于哪一段
void PushUp(int rt) {
	if(ID[rt<<1] == ID[rt<<1|1])
		ID[rt]=ID[rt<<1];
	else
	ID[rt] = -1;
}
void PushDown(int rt,int m) {
	if(ID[rt]!=-1)
	{
		ID[rt<<1] = ID[rt];
		ID[rt<<1|1] = ID[rt];
	}
}
void build(int l,int r,int rt) {
	if (l == r) {
		ID[rt]=-1;
		return ;
	}
	int m = (l + r) >> 1;
	build(lson);
	build(rson);
	PushUp(rt);
}
void update(int L,int R,int c,int l,int r,int rt) {
	if (L <= l && r <= R) {
		ID[rt] = c;
		return ;
	}
	PushDown(rt , r - l + 1);
	int m = (l + r) >> 1;
	if (L <= m) update(L , R , c , lson);
	if (m < R) update(L , R , c , rson);
	PushUp(rt);
}
LL query(int L,int R,int l,int r,int rt) {
	if (L <= l && r <= R) {
		return ID[rt];
	}
	PushDown(rt , r - l + 1);
	int m = (l + r) >> 1;
	LL ret = 0;
	if (L <= m) ret += query(L , R , lson);
	if (m < R) ret += query(L , R , rson);
	return ret;
}

map<int ,int >my;
struct bian
{
	int l,r,len;
	int id;
};
int num[800010];//用来记录输入的所有的数 用于去离散化
bian edge[100010];
int qus[100010];//记录询问
int cmp(bian a,bian b)
{
	return a.len<b.len;
}
int arr[800010];
int main()
{
	int i,a,b;
	int t,cas=1;
	int n;
	int ji;
	while(scanf("%d",&n)!=EOF)
	{
		my.clear();

		ji=0;
		for(i=0;i<n;i++)
		{
			scanf("%d%d",&a,&b);
			edge[i].l=a;
			edge[i].r=b;
			edge[i].len=b-a;
			edge[i].id=i+1;
			num[ji++]=a;
			num[ji++]=b;
		}

		int m;
		scanf("%d",&m);
		for(i=0;i<m;i++)
		{
			scanf("%d",&qus[i]);
			num[ji++]=qus[i];
		}

		sort(edge,edge+n,cmp);
		sort(num,num+ji);
		int ji2=1;
		for(i=1;i<ji;i++)
		{
			if(num[i]!=num[i-1])
				num[ji2++]=num[i];
		}

		ji=ji2;
		for(i=0;i<ji;i++)
			my[num[i]]=i+1; 

		build(1,ji,1);
		for(i=n-1;i>=0;i--)//边长从大到小排序, 所以从后往前,边长短的会覆盖掉
		{
			int l=my[edge[i].l];
			int r=my[edge[i].r];
			update(l,r,edge[i].id,1,ji,1);
		}
		for(i=0;i<m;i++)
			printf("%d\n",query(my[qus[i]],my[qus[i]],1,ji,1));
	}
	return 0;
}

时间: 2024-11-08 01:35:51

URAL1987. Nested Segments 线段树的相关文章

POJ 1436 Horizontally Visible Segments (线段树&amp;#183;区间染色)

题意   在坐标系中有n条平行于y轴的线段  当一条线段与还有一条线段之间能够连一条平行与x轴的线不与其他线段相交  就视为它们是可见的  问有多少组三条线段两两相互可见 先把全部线段存下来  并按x坐标排序  线段树记录相应区间从右往左当前可见的线段编号(1...n)  超过一条就为0  然后从左往右对每条线段  先查询左边哪些线段和它是可见的  把可见关系存到数组中  然后把这条线段相应区间的最右端可见编号更新为这条线段的编号  最后暴力统计有多少组即可了 #include <cstdio>

Poj1436Horizontally Visible Segments线段树

#include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set> #include <qu

Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树 矩阵面积并

D. Vika and Segments Vika has an infinite sheet of squared paper. Initially all squares are white. She introduced a two-dimensional coordinate system on this sheet and drew n black horizontal and vertical segments parallel to the coordinate axes. All

(中等) POJ 1436 Horizontally Visible Segments , 线段树+区间更新。

Description There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they can be connected by a horizontal line segment that does not have any common points with other vertical segments.

CF Educational Codeforces Round 10 D. Nested Segments 离散化+树状数组

题目链接:http://codeforces.com/problemset/problem/652/D 大意:给若干个线段,保证线段端点不重合,问每个线段内部包含了多少个线段. 方法是对所有线段的端点值离散化,按照左端点从大到小排序,顺着这个顺序处理所有线段,那么满足在它内部的线段一定是之前已经扫到过的.用树状数组判断有多少是在右端点范围内. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>

codeforces 652D Nested Segments 离散化+树状数组

题意:给你若干个区间,询问每个区间包含几个其它区间 分析:区间范围比较大,然后离散化,按右端点排序,每次更新树状数组中的区间左端点,查询区间和 注:(都是套路) #include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> using name

Codeforces 610D Vika and Segments 线段树+离散化+扫描线

可以转变成上一题(hdu1542)的形式,把每条线段变成宽为1的矩形,求矩形面积并 要注意的就是转化为右下角的点需要x+1,y-1,画一条线就能看出来了 #include<bits/stdc++.h> #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #pragma comment(linker,

POJ1436Horizontally Visible Segments线段树+lazy

判断3条线段是否联通,如果任意2条线段联通,则3条线段联通:开一个hash[i][j]保存第i条线段和第j条线段的关系,每次插入新的线段前都需要先判断此直线是否与前面的其他线段联通,再将这条线段插入:PS:要注意的一点是需要先对所有的线段关于x坐标进行排序,然后再按照熟顺序插入线段: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <

bnu36905 Nested Segments 离散化+线段树

bnu36905 Nested Segments 离散化+线段树区间更新 也可以用离散化+set(或双向链表) #include <cstdio> #include <ctime> #include <cstdlib> #include <cstring> #include <queue> #include <string> #include <set> #include <stack> #include &l