题解 CF160E 【Buses and People】
题意:
给定n辆公交车 \(t_i\)时间从\(s_i\)出发去\(f_i\),
有m个人,\(b_i\)时间或之后从\(l_i\)去\(r_i\)
求每个人最早搭哪辆车。
即:对于每个人 求公交车\(t_i\)最小,且\(t_i\ge b_i\),\(l_i\ge s_i\),\(f_i\le r_i\)。
分析:
离散化时间。按照\(l_i\)排序,再按照公交->人 排序
按时间建立线段树。
按照排好序的将车插入线段树,线段树维护\(f_i\)的最大值。
查询时,查询\([1,b_i]\)区间中满足\(f_i\le r_i\)的最小\(t_i\)
(按照顺序插入,保证了\(l_i\ge s_i\))
再次体会到线段树的强大。
@jljljl 太强了 我看ta题解懂的。代码可能会相似。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
#define rd(x) scanf("%d",&x)
typedef long long LL;
const int N=1e5+10,inf=0x3f3f3f3f;
int n,m,lsh[N<<1],ans[N],tr[N<<3];
struct pos{
int t,l,r,tp,id;
}tmp[N<<1];
bool cmp(pos x,pos y){ return (x.l==y.l)?(x.tp>y.tp):(x.l<y.l); }
void pushup(int rt){ tr[rt]=(tmp[tr[rt<<1]].r>tmp[tr[rt<<1|1]].r)?tr[rt<<1]:tr[rt<<1|1]; }
void update(int rt,int l,int r,int x,int id){
if(l==r){
if(tmp[tr[rt]].r<tmp[id].r) tr[rt]=id; //维护最大r(以序号形式)
return;
}
int mid=l+r>>1;
if(x<=mid) update(rt<<1,l,mid,x,id);
else update(rt<<1|1,mid+1,r,x,id);
pushup(rt);
}
int query(int rt,int l,int r,int x,int id){
if(tmp[tr[rt]].r<tmp[id].r||lsh[r]<tmp[id].t) return -1;
//公交车的最大r还不如查询r 或者公交车的t小于查询t
if(l==r) return tmp[tr[rt]].id;
int mid=l+r>>1;
int ret=query(rt<<1,l,mid,x,id);
if(ret!=-1) return ret;
ret=query(rt<<1|1,mid+1,r,x,id);
return ret;
}
int main(){
rd(n);rd(m);
rep(i,1,n){
rd(tmp[i].l),rd(tmp[i].r),rd(tmp[i].t);
tmp[i].tp=1,tmp[i].id=i;
lsh[i]=tmp[i].t;
}
rep(i,1,m){
rd(tmp[i+n].l),rd(tmp[i+n].r),rd(tmp[i+n].t);
tmp[i+n].tp=0,tmp[i+n].id=i;
lsh[i+n]=tmp[i+n].t;
}
sort(lsh+1,lsh+n+m+1);sort(tmp+1,tmp+n+m+1,cmp);
int tot=unique(lsh+1,lsh+n+m+1)-lsh-1;
for(int i=1;i<=n+m;i++){
int nwt=lower_bound(lsh+1,lsh+tot+1,tmp[i].t)-lsh;
if(tmp[i].tp) update(1,1,tot,nwt,i);
else ans[tmp[i].id]=query(1,1,tot,nwt,i);
}
rep(i,1,m) printf("%d ",ans[i]);
return 0;
}
QwQwQ