Buses and People + CodeForces - 160E

Buses and People 三维处理

题目大意:有n辆公交车,每辆公交车有s(起始点),f(终点),t(发车时间) ,有m个人,每个人有l(起点),r(终点),t(出现时间)
对于一个人,当t(人)<=t(车), s<=l,r <=f 时就能上这辆车,问能上的发车时间最早的是那一辆

类似三维偏序问题,有三个维度需要我们解决。首先,车和人都有l,r,t,三个属性,先按照l排序,解决第一维,这样,对于一个人,前面的所有的车都是可能上去的。剩下的两个维度用线段树来解决,线段树维护区间最大值。线段树下标对应的是t,维护的最大值是r。把车和人在一起排序,从头遍历,是车,就在t位置插入r,是人,就在线段树t位置到末端查询满足小于r的最小的下标对应的id(也就是车的id)。

怎么也没想到可以用一个线段树直接解决两维。
查询到一个人,前面已经插入的车的l一定都比它小了;线段树查询的是t到末端,t大于人的车一定在其中;线段树维护的是r最大值,只要查询的区间内的r有大于等于此人的r,那么这个人就一定能上车。

排序解决一维,线段树解决一维,维护的最大值解决一维。

#include <cstdio>
#include <algorithm>
#include <cmath>
#define Mid ((a[k].l+a[k].r)>>1)
#define cl (k<<1)
#define cr (k<<1|1)
#define Max 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int maxn=2e5+5;

struct Q{
    int l,r,t, id,tp;//tp==0 车, tp==1 人
    friend bool operator <(Q a, Q b){
        if(a.l!=b.l) return a.l < b.l;	//按照l排序,若l相同,人在后
        return a.tp < b.tp;
    }
}q[maxn*2];
struct N{
    int l,r;
    int ma,id;
}a[maxn*4];
int dis[maxn*2], cur;//离散化
int ans[maxn];

void build(int k,int l,int r){
    a[k].l=l, a[k].r=r;
    a[k].ma = -1;
    a[k].id = -1;
    if(l==r) return;
    int mid=Mid;
    build(cl,l,mid), build(cr,mid+1,r);
}
void updata(int k,int i,int x, int id){
    if(a[k].l==a[k].r){
        if(a[k].ma < x){
            a[k].ma = x;
            a[k].id = id;
        }
        return;
    }
    int mid=Mid;
    if(i<=mid) updata(cl,i,x,id);
    else       updata(cr,i,x,id);

    if(a[k].ma < a[cl].ma){
        a[k].ma = a[cl].ma;
        a[k].id = a[cl].id;
    }
    if(a[k].ma < a[cr].ma){
        a[k].ma = a[cr].ma;
        a[k].id = a[cr].id;
    }
}
int get(int k,int l,int r,int x){//返回符合要求的最小的下标 对应的id

    if(a[k].l==a[k].r && a[k].ma>=x)
        return a[k].id;

    int mid=Mid;
    int ret=Max;
    if(l<=mid && a[cl].ma>=x ){	//若左边有符合的,可以直接返回,左边的下标(t)一定比右边小
        ret = get(cl,l,r,x);
        if(ret!=Max) return ret;
    }
    if(r>mid && a[cr].ma>=x ){
        ret = get(cr,l,r,x);
        if(ret!=Max) return ret;
    }
    return ret;
}
int gs(int x){return lower_bound(dis+1,dis+1+cur,x)-dis; }//离散化

int main()
{
    int n,m,qn=0;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++){
        qn++;
        scanf("%d%d%d",&q[qn].l, &q[qn].r, &q[qn].t);
        q[qn].tp = 0;
        q[qn].id = i;
        dis[++cur] = q[qn].t;
    }
    for(int i=1; i<=m; i++){
        qn++;
        scanf("%d%d%d",&q[qn].l, &q[qn].r, &q[qn].t);
        q[qn].tp = 1;
        q[qn].id = i;
        dis[++cur] = q[qn].t;
    }

    sort(dis+1,dis+cur+1);
    cur = unique(dis+1,dis+cur+1) - (dis+1);

    sort(q+1,q+1+qn);
    build(1,1,cur);

    for(int i=1; i<=qn; i++){
        if(q[i].tp==0){//车
            updata(1, gs(q[i].t) ,q[i].r, q[i].id);
        }else{
            int x=get(1, gs(q[i].t), cur, q[i].r);
            if(x==Max)//没找到
                ans[q[i].id] = -1;
            else
                ans[q[i].id] = x;
        }
    }
    for(int i=1; i<=m; i++){
        printf("%d ",ans[i]);
    }
    printf("\n");

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值