CodeForces160E Buses and People 线段树 区间合并 离散化

思路来源:https://blog.csdn.net/heucodesong/article/details/89181542
题意:一堆人要坐公交车到目的地,给你n个公交车的起点、终点、出发时间(而且从起点到终点就是这个时间,秒过去)。给你m个人的上车点、下车点、开始等车的时间,问你每个人坐哪辆车合适,若有合适的车,输出车的编号,若没有,输出-1。
思路:先说下开始的莽撞思路(T了):首先拿到这个就想,先把公交车按时间排序,然后对于每个人,在排好序的公交车里二分找到第一个时间大于人的等车时间的,然后一个个找,找到第一个合适的。果断T了。
以上思路太简单,直接当思维题做了,应该用线段树。
1、首先数据范围1e9,数据量1e5,所以离散化。
2、题解说 这是个区间合并,然鹅我并不感觉是个区间合并,或者说我现在都没搞明白区间合并是个什么鬼。(这一条是废话,无视就好)
3、真正思路:
因为要满足 l车<=l人,r人<=r车,t人<=t车 这三个限制条件缺一不可!!!
所以我们对于三个限制条件的处理方法是:
根据时间t建立线段树,且按左端点l重新排序后(注意这一步排序是把车和人的信息一起排序,若左端点相同,就按id排序,这样保证了车一定在人的前面)。
若是车,就更新线段树,若是人,就查询线段树。艾玛这个题,我现在还把控不了,比着题解打了一遍还是不太行啊,没领悟到精髓。先留坑吧,代码里也有注释也可以看看。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
#define cl(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=2e5+10;
int n,m,cnt;
int lr[maxn<<1],tt[maxn],ans[maxn];
struct node{
	int l,r,t,id;
}q[maxn];
bool cmp(node x,node y){
	if(x.l==y.l) return x.id<y.id;
	return x.l<y.l;
}
struct node2{//r_bound 每个节点存的是该时间最大的 终止坐标
	int l,r,r_bound,id;//id只有叶子结点有,存该时间点的车辆id 
}t[maxn<<2];
void pushup(int k){
	t[k].r_bound=max(t[k<<1].r_bound,t[k<<1|1].r_bound);
}
void build(int k,int l,int r){
	t[k].l=l,t[k].r=r;
	if(l==r){
		t[k].r_bound=0;
	}else{
		int mid=(l+r)>>1;
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		pushup(k);
	}
}
void updata(int k,int p,int r_bound,int id){
	if(t[k].l==t[k].r){
		t[k].r_bound=r_bound;
		t[k].id=id; 
	}else{
		int mid=(t[k].l+t[k].r)>>1;
		if(p<=mid) updata(k<<1,p,r_bound,id);
		if(mid<p) updata(k<<1|1,p,r_bound,id);
		pushup(k);
	}
}
int query(int k,int p,int r_bound){//p 符合条件的最小时间
	if(t[k].r_bound<r_bound){//若当前车达到的最远不能到人的最远就不行 
		return -1;
	}else{//若当前能达到
		if(t[k].l==t[k].r){//若是叶结点 
			return t[k].id;//返回当前车的编号 
		}else{
			int mid=(t[k].l+t[k].r)>>1;
			int ans=-1;
			//这里应该是和mid比!!! 
			if(p<=mid){//若左子树当前人的时间比车最晚到的时间要早(人等车 
				ans=query(k<<1,p,r_bound);
				//关键语句 在该结点的子树能达到的前提下
				if(ans!=-1) return ans;// 若左子树不能达到  那右子树一定能达到 
			}
			return query(k<<1|1,p,r_bound); 
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	cnt=0;
	for(int i=1;i<=n+m;i++){//输入
		scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].t);
		q[i].id=i; 
		lr[++cnt]=q[i].l;
		lr[++cnt]=q[i].r;
		tt[i]=q[i].t;
	}
	//下面离散化
	sort(lr+1,lr+cnt+1);
	sort(tt+1,tt+n+m+1);
	int size_lr=unique(lr+1,lr+cnt+1)-(lr+1);
	int size_tt=unique(tt+1,tt+n+m+1)-(tt+1);
	for(int i=1;i<=n+m;i++){
		q[i].l=lower_bound(lr+1,lr+size_lr+1,q[i].l)-lr;
		q[i].r=lower_bound(lr+1,lr+size_lr+1,q[i].r)-lr;
		q[i].t=lower_bound(tt+1,tt+size_tt+1,q[i].t)-tt;
	}
	sort(q+1,q+n+m+1,cmp);//重新按左端点排序 
	build(1,1,n+m);
	for(int i=1;i<=n+m;i++){//遍历所有车和人 
		if(q[i].id<=n){//若是车 
			updata(1,q[i].t,q[i].r,q[i].id); 
		}else{//若是人
			ans[q[i].id]=query(1,q[i].t,q[i].r);
		}
	}
	for(int i=n+1;i<n+m;i++){
		printf("%d ",ans[i]);
	}printf("%d\n",ans[n+m]);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值