思路来源: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;
}