CodeForces - 160E - Buses and People(线段树+离散化+二分)

题目链接:http://codeforces.com/problemset/problem/160/E

题目:

The main Bertown street is represented by a straight line. There are 109 bus stops located on the line. The stops are numbered with integers from 1 to 109 in the order in which they follow on the road. The city has n buses. Every day the i-th bus drives from stop number si to stop number fi (si < fi), it stops on all intermediate stops and returns only at night. The bus starts driving at time ti and drives so fast that it finishes driving also at time ti. The time ti is different for all buses. The buses have infinite capacity.

Bertown has m citizens. Today the i-th person should get from stop number li to stop number ri (li < ri); the i-th citizen comes to his initial stop (li) at time bi. Each person, on the one hand, wants to get to the destination point as quickly as possible, and on the other hand, definitely does not want to change the buses as he rides. More formally: the i-th person chooses bus j, with minimum time tj, such that sj ≤ liri ≤ fj and bi ≤ tj.

Your task is to determine for each citizen whether he can ride to the destination point today and if he can, find the number of the bus on which the citizen will ride.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 105) — the number of buses and the number of people.

Then n lines follow, each of them contains three integers: sifiti (1 ≤ si, fi, ti ≤ 109, si < fi) — the description of the buses. It is guaranteed that all ti-s are different.

Then m lines follow, each of them contains three integers: liribi (1 ≤ li, ri, bi ≤ 109, li < ri) — the Bertown citizens' description. Some bi-s could coincide.

Output

In the first line print m space-separated integers: the i-th number should be equal either to -1, if the person number i can't get to the destination point, or to the number of the bus that will ride the person number i. The buses are numbered with integers from 1 to n in the input order.

Examples

Input

4 3
1 10 10
5 6 2
6 7 3
5 7 4
5 7 1
1 2 1
1 10 11

Output

4 1 -1

Input

1 1
1 1000000000 1000000000
1 1000000000 1000000000

Output

1

 

题目大意:
有n辆巴士,m个人,巴士有自己的出发站 结束站 和出发时间  每个乘客也有自己的出发站 结束站 出发时间 。最后让你输出每个乘客会做哪一辆车完成它的目标,注意乘客只允许通过一辆车一次性完成目标。
这里关于多个车如果同时能完成目标的话,应该保证时间最短。

解题思路:

注意需要那三个条件都符合才可以。
首先我们把所有的车和人放在一起全部排序,
排序第一关键字:左端点
排序第二关键字:id

我们首先将所有的数据输入进行排序,按照排序后的顺序依次进行操作,如果当前是车,就将这辆车的信息按照出发时间更新入线段树中(题目保证出发时间不同),我们线段树只需保存右端点即可,因为是按照左端点排序的,当我们碰到要查询乘客坐哪辆车的时候,只有线段树中已经存的结点才是有可能符合要求的,就直接对线段树内的结点进行查询即可,这也就是第二关键字的含义,要保证车排在人的面前。接着排完序之后的顺序,如果我们当前的是人的话,那就在当前的线段树中查询一个符合要求的结点即可。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
int n,m;
const int INF=2e5+5;
int a[INF];
struct node{
	int from;
	int to;
	int t;
	int id;
}g[INF];
int v[INF];
struct Node{
	int right;
	int left;
	int di;
	int rx;
}f[4*INF];
bool cmp(node p1,node p2)//排序,先以起始站从小到大排,再以序号从小到大排 
{
	if(p1.from ==p2.from )
	{
		return p1.id <p2.id  ;
	}
	else {
		return p1.from <p2.from ;
	}
}
void pushup(int ans)
{
	f[ans].rx =max(f[ans<<1].rx ,f[ans<<1|1].rx ); 
}
void build(int ans,int l,int r)//建树 
{
	f[ans].right =r;f[ans].left =l;
	f[ans].di =0;f[ans].rx =0;
	if(l==r)return;
	int mid=(f[ans].left +f[ans].right )>>1;
	build(ans<<1,l,mid);
	build(ans<<1|1,mid+1,r);
}
void update(int ans,int x,int r,int d)//更新 
{
	if(f[ans].left ==f[ans].right )
	{
		f[ans].di =d;
		f[ans].rx =r;
		return ;
	}
	int mid=(f[ans].left +f[ans].right )>>1;
	if(x<=mid)
	{
		update(ans<<1,x,r,d);
	}
	else {
		update(ans<<1|1,x,r,d);
	}
	pushup(ans);
}
int getsum(int ans,int x,int r)
{
	if(f[ans].rx <r)return -1;
	if(f[ans].left ==f[ans].right ){
		return f[ans].di ;
	}
	int mid=(f[ans].left +f[ans].right )>>1;
	if(x<=mid)//注意要保证时间尽量短 
	{
		int an=getsum(ans<<1,x,r);
		if(an>0)return an;
	}
    return getsum(ans<<1|1,x,r);
//    if(x<=mid&&f[ans<<1].rx >=r){//这样写错误的原因是只满足f[ans<<1].rx >=r这个条件,不能保证返回值不是-1, 
//    	return getsum(ans<<1,x,r);//因为还受x的影响,可能x满足的区域内上面那个条件不满足。 
//	}
//	else {
//		return getsum(ans<<1|1,x,r);
//	}
}
int main()
{
	scanf("%d%d",&n,&m);
	int i,j,k,val;
	int u,w;
	for(i=1,u=0,w=0;i<=n+m;i++)
	{
		scanf("%d%d%d",&j,&k,&val);
		g[++u].from =j;g[u].to =k;
		g[u].id =i;g[u].t =val;
		v[++w]=g[u].t ;
	}
	sort(v+1 ,v+w+1 );//去重排序 ,对时间点进行离散化 
	int cnt=unique(v+1,v+1+w)-v-1;
	sort(g+1,g+1+u,cmp);
	build(1,1,cnt );
	for(i=1;i<=n+m;i++)
	{
		int cn=lower_bound(v+1,v+1+cnt ,g[i].t )-v;
		if(g[i].id <=n)
		{
			update(1,cn,g[i].to ,g[i].id );
		}
		else {
			int ans=getsum(1,cn,g[i].to );
			a[g[i].id ]=ans;
		}
	}
	for(i=n+1;i<n+m;i++)
	{
		printf("%d ",a[i]);
	}
	printf("%d",a[n+m]);
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值