题目链接:点击查看

题目大意:(网上复制一下别人的题意。。懒)

有n辆公交车,每辆公交车有s(起始点),f(终点),t(发车时间) (行驶不需要时间)

有m个人,每个人有l(起点),r(终点),t(出现时间)

每个人出现后会选择最早经过他且可行的公交车

(即满足s<=l,r<=f,且公交车发车时间晚于人出现时间)

输出每个人会选择那一辆公交车

如果没有符合条件的公交车输出-1

题目分析:这个题目一看到题目中的“sj ≤ liri ≤ fj and bi ≤ tj”,感觉就是偏序问题,只不过变成了三维,之前做过最简单的一维是sort排个序就行,二维的一般是给定两个区间[l,r],然后统一对某个端点排序,然后对另一个端点用线段树就能解决,现在上升到了三维,在给出区间[l,r]的基础上,还增加了一个时间t的约束,那么我们应该先对其中的一个区间端点排序,我选择了对左区间排序,然后还剩下了右区间和时间t,题目中说了t都互不相等,我们可以直接对t建线段树,让t当做下标,那么维护的权值肯定和右区间端点r有关系,那么我们需要维护什么呢?通过分析之后我们发现,如果我们已经建树后,要找满足条件(即在区间[l,r]内t最小)的t,我们在查询的时候会从根节点出发,一步一步尽量向左区间移动,因为在线段树中以t为下标建树,并且t互不相等,那么可以保证左边的t必定小于右边的t,那么尽量向左区间下移的结果就是所求答案了,我们接下来需要考虑如何在向下移动的时候,一定满足在区间[l,r]中呢,首先我们对于左区间端点l升序处理过了,可以保证当遍历到任意一个查询的时候,这个查询左区间端点之前的公交车已经被加入到线段树中了(即左区间端点l的条件已经满足),让t满足条件并且取最小可以在查询的时候边判断边下传,可以保证下传的时候都是在满足t的范围内(即公交车的t要小于人的t)下传的,这样我们就可以想到,能不能在线段树中维护右区间端点的最大值来让每次下传都满足条件呢,每次只要下传的时候判断一下右区间是否在维护的最大值的范围内即可轻易满足右区间的条件,因为在某一个时间t的时候,公交车可以开到最大的右端点,那么只要让所求的右端点小于这个最大值,就能取到这个时间t,从而同时满足了l和t的约束,这样一来因为每个时间t都是互不相同的,所以可以通过线段树来解决这个三维偏序问题。

同样需要注意一下,t的范围过大,需要离散化一下,这里不多赘述了,上代码吧

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e6+100;vector<int>v;int ans[N];struct qu
{int l,r,t,id;bool operator<(qu a)const{return l<a.l; }
}qu1[N],qu2[N];//qu1储存的是公交车信息,qu2储存的是人的信息struct Node
{int l,r,mmax,id;
}tree[N<<2];void pushup(int k)
{tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);
}void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].mmax=0;tree[k].id=-1;if(l==r)return;int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}void update(int k,int pos,int val,int id)
{if(tree[k].l==tree[k].r){tree[k].mmax=val;tree[k].id=id;return;}int mid=tree[k].l+tree[k].r>>1;if(mid>=pos)update(k<<1,pos,val,id);elseupdate(k<<1|1,pos,val,id);pushup(k);
}int query(int k,int num,int b)
{if(tree[k].mmax<num)return -1;if(tree[k].l==tree[k].r)return tree[k].id;int mid=tree[k].l+tree[k].r>>1;int ans=-1;if(mid>=b){ans=query(k<<1,num,b);if(ans>0)return ans;}return query(k<<1|1,num,b);
}int getid(int num)//离散化:获得新编号
{return lower_bound(v.begin(),v.end(),num)-v.begin()+1;
}int main()
{
//  freopen("input.txt","r",stdin);int n,m;while(scanf("%d%d",&n,&m)!=EOF){v.clear();for(int i=1;i<=n;i++){scanf("%d%d%d",&qu1[i].l,&qu1[i].r,&qu1[i].t);v.push_back(qu1[i].t);qu1[i].id=i;}for(int i=1;i<=m;i++){scanf("%d%d%d",&qu2[i].l,&qu2[i].r,&qu2[i].t);qu2[i].id=i;v.push_back(qu2[i].t);}sort(v.begin(),v.end());//离散化:排序v.erase(unique(v.begin(),v.end()),v.end());//离散化:去重sort(qu1+1,qu1+1+n);//对公交车的左区间端点排序sort(qu2+1,qu2+1+m);//对人的左区间端点排序int cnt=1;build(1,1,v.size());//建树,这里一定要记着,线段树是要用离散化后t的个数来建树,一开始习惯性的用n建树,结果连样例都过不去。。自闭for(int i=1;i<=m;i++){/*       if(qu1[cnt].l>qu2[i].l)//不知道为什么加了这么一段剪枝会WA。。(可能是我太菜了){ans[qu2[i].id]=-1;continue;}*/while(qu1[cnt].l<=qu2[i].l&&cnt<=n)//每次先把左区间人左边的公交车全部加入线段树中{update(1,getid(qu1[cnt].t),qu1[cnt].r,qu1[cnt].id);cnt++;}ans[qu2[i].id]=query(1,qu2[i].r,getid(qu2[i].t));}for(int i=1;i<=m;i++)printf("%d ",ans[i]);cout<<endl;}return 0;
}

CodeForces - 160E Buses and People(线段树+三维偏序)相关推荐

  1. Codeforces 444C DZY Loves Colors 线段树区间更新

    // Codeforces 444C DZY Loves Colors 线段树区间更新// 题目链接:// http://codeforces.com/problemset/problem/444/C ...

  2. CodeForces - 1557D Ezzat and Grid(线段树+dp)

    题目链接:点击查看 题目大意:给出 nnn 个 010101 串,现在问最少需要删掉多少个串,才能使得剩下的串拼起来是连通的 规定两个 010101 串是连通的,当且仅当存在至少一列,在两个串中都为 ...

  3. CodeForces - 1527E Partition Game(dp+线段树)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的数列,现在需要将其划分成 kkk 段,使得贡献和最小 对于每段区间 [l,r][l,r][l,r] 的贡献为,其中每个数字,其最后一次出现的位置 ...

  4. codeforces 581B Luxurious Houses(线段树点更新,区间查询)

    题目链接: http://codeforces.com/problemset/problem/581/B 题目大意: 给n个不同高度的房子,要求当对于第i个房子来说,他要严格的比后面的房子都高. 思路 ...

  5. codeforces 85D. Sum of Medians(线段树or分块)

    题目链接:codeforces 85D. Sum of Medians 题意: add x 表示向集合中添加x(添加x的时候保证x是第一次被添加入集合) del x 表示从集合中删除x (删除x的时候 ...

  6. Codeforces 85D Sum of Medians(线段树)

    题目链接:Codeforces 85D - Sum of Medians 题目大意:N个操作,add x:向集合中添加x:del x:删除集合中的x:sum:将集合排序后,将集合中所有下标i % 5 ...

  7. codeforces 609F Frogs and mosquitoes 线段树+二分+multiset

    http://codeforces.com/problemset/problem/609/F There are n frogs sitting on the coordinate axis Ox. ...

  8. CodeForces - 960F[动态开点线段树优化dp]详解

    题意:给一张有向图,每条边有边权与编号,求一条最长的路径,这条路径的边权与编号都是递增的.(编号指输入顺序) 首先我们回忆一下普通得LIS得做法:就是dp[i]以第i个结尾得最长上升子序列的长度,那么 ...

  9. Codeforces 524E Rooks and Rectangles 线段树

    区域安全的check方法就是, 每行都有哨兵或者每列都有哨兵,然后我们用y建线段树, 维护在每个y上的哨兵的x的最值就好啦. #include<bits/stdc++.h> #define ...

最新文章

  1. 什么是两阶段提交协议2PC CAP
  2. RHEL5 Silent方式安装Oracle 11gR2指南
  3. Linux kernel 学习笔记(1) --分段分页保护机制
  4. 搜索推荐炼丹笔记:CVR预估中的延迟反馈问题
  5. java堆 数据结构 堆_Java中的紧凑堆外结构/组合
  6. 【RS码1】系统RS码编码原理及MATLAB实现(不使用MATLAB库函数)
  7. python槽格式里填啥_用于填充插槽的网络挂钩
  8. 686. Repeated String Match
  9. 《SQL基础教程》((日)MICK)PDF
  10. BLDC无刷直流电机驱动电路-硬石电子
  11. 视频教程-【CVPR2018】A Causal And-Or Graph Model for Visibil-计算机视觉
  12. 建议更新IE浏览器的版本
  13. 安装完固态硬盘后计算机里没显示,如何解决安装固态硬盘后系统看不到的问题[详细介绍]...
  14. 简单易懂读《重构》 - Speculative Generality (高估未来的可能性)
  15. 东北酱油 模拟赛 期望dp
  16. matplotlib对excel数据可视化
  17. VScode 显示垂直标尺
  18. 用科傻软件,求平面网和高程网的平差
  19. db9接口(db9接口详细接线图)
  20. 【很逗,很经典】【与靠谱IT男的浪漫闪婚记】——转个很可爱的帖子,貌似男女猪脚是咱IT人士呢

热门文章

  1. Nginx的rewrite案例之防盗链
  2. Java并发编程的基础-为什么要复位
  3. 对HTTP/2 支持
  4. 寻找获取Bean 的入口
  5. OAuth2.0在项目中认证流程介绍
  6. 新版本springboot-springboot与springcloud理解误区
  7. 单点登录之SessionExpireFilter重置session有效期
  8. activemq安全机制
  9. RocketMQ消息发送之pull和push
  10. java 不能反序列化_java中的序列化与反序列化