题意:
有n个公交车,每个公交车有起始位置s,终止位置f,到达终点的时间t
有m个乘客,每个乘客有上车位置l,下车位置r,上车时间b
乘客能上车的前提是l>=s,r<=f,b<=t
问每个乘客能做的公交车中,发车时间最早的车编号
数据范围n<=1e5,其他数据<=1e9,保证所有车的发车时间不同
解法:
将车和乘客按左端点从小到大排序,降一维。
双指针,遍历乘客,将左端点小于等于当前乘客的车加入线段树,
线段树每个节点表示时间,存储时间为t的车右端点
查询就是线段树中找车的时间晚于乘客的所有位置中,满足右端点大于乘客的最小时间,
可以在树上二分,优先找左子树,还可以维护一个区间max进行剪枝。
时间需要离散化
ps:
题目已经说了所有车的发车时间不同,似乎也暗示了从时间入手
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
struct E1{
int s,f,t,id;
}e[maxm];
struct E2{
int l,r,b,id;
}q[maxm];
bool cmp1(E1 a,E1 b){
return a.s<b.s;
}
bool cmp2(E2 a,E2 b){
return a.l<b.l;
}
//
int a[maxm<<2],idx[maxm<<2];
int xx[maxm],num;
int ans[maxm];
int n,m;
void pushup(int node){
a[node]=max(a[node*2],a[node*2+1]);
}
void update(int x,int val,int idd,int l,int r,int node){
if(l==r){
a[node]=val;
idx[node]=idd;
return ;
}
int mid=(l+r)/2;
if(x<=mid)update(x,val,idd,l,mid,node*2);
else update(x,val,idd,mid+1,r,node*2+1);
pushup(node);
}
int ask(int st,int ed,int val,int l,int r,int node){//发车时间[x,n]中满足右端点>val的最左边的车
if(a[node]<val)return -1;
if(l==r)return idx[node];
int mid=(l+r)/2;
int ans=-1;
if(st<=mid)ans=ask(st,ed,val,l,mid,node*2);
if(ans==-1&&ed>mid)ans=ask(st,ed,val,mid+1,r,node*2+1);
return ans;
}
//
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&e[i].s,&e[i].f,&e[i].t);
e[i].id=i;
xx[++num]=e[i].t;
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].b);
q[i].id=i;
xx[++num]=q[i].b;
}
sort(e+1,e+1+n,cmp1);
sort(q+1,q+1+m,cmp2);
//
sort(xx+1,xx+1+num);
num=unique(xx+1,xx+1+num)-xx-1;
for(int i=1;i<=n;i++){
e[i].t=lower_bound(xx+1,xx+1+num,e[i].t)-xx;
}
for(int i=1;i<=m;i++){
q[i].b=lower_bound(xx+1,xx+1+num,q[i].b)-xx;
}
//
int k=1;
for(int i=1;i<=m;i++){
while(k<=n&&e[k].s<=q[i].l){//将左端点早于当前乘客的所有车加入线段树
update(e[k].t,e[k].f,e[k].id,1,num,1);
k++;
}
ans[q[i].id]=ask(q[i].b,num,q[i].r,1,num,1);
}
for(int i=1;i<=m;i++){
printf("%d ",ans[i]);
}
return 0;
}