下笔春蚕食叶声。

题解 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;
}
posted @ 2020-11-02 07:30  ACwisher  阅读(76)  评论(0编辑  收藏  举报