CodeForces - 160E(线段树单点更新+离散)


题目链接:点击打开链接


题目大意:

有n辆巴士,m个人,巴士有自己的出发站 结束站 和出发时间  每个乘客也有自己的出发站 结束站 出发时间 。最后让你输出每个乘客会做哪一辆车完成它的目标,注意乘客只允许通过一辆车一次性完成目标。

这里关于多个车如果同时能完成目标的话,应该是默认坐第一辆可以完成目标的车,题目好像没有明说。


解题思路:

首先我们把所有的车和人放在一起全部排序,

排序第一关键字:左端点

排序第二关键字:id


我们首先将所有的数据输入进行排序,按照排序后的顺序依次进行操作,如果当前是车,就将这辆车的信息按照出发时间更新入线段树中(题目保证出发时间不同),我们线段树只需保存右端点即可,因为是按照左端点排序的,当我们碰到要查询乘客坐哪辆车的时候,只有线段树中已经存的结点才是有可能符合要求的,就直接对线段树内的结点进行查询即可,这也就是第二关键字的含义,要保证车排在人的面前。接着排完序之后的顺序,如果我们当前的是人的话,那就在当前的线段树中查询一个符合要求的结点即可。


以下代码:

#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
using namespace std;
typedef long long ll;
const int INF=1e9+7;
const int N=1e5+7;
const int MOD=1e9+7;
int ans[N];
vector<int> v;
int getid(int x){ return lower_bound(v.begin(),v.end(),x)-v.begin()+1; }
struct tree     //线段树结点 存右端点和车的编号
{
    int l,r,mid;
    int rx;
    int idx;
}t[N<<3];
struct node     //保存车和乘客的信息
{
    int l,r,t;
    int id;
    bool operator<(const node &p) const
    {
        if(l==p.l)
            return id<p.id;
        return l<p.l;
    }
}g[N<<1];

void pushup(int rt)
{
    t[rt].rx=max(t[lson].rx,t[rson].rx);
}
void build(int l,int r,int rt)
{
    int m=(l+r)>>1;
    t[rt].l=l,t[rt].r=r;
    t[rt].mid=m;
    if(l==r)
    {
        t[rt].rx=-INF;
        return ;
    }
    build(l,m,lson);
    build(m+1,r,rson);
    pushup(rt);
}
void update(int pos,int id,int flag,int rt)     //单点更新线段树
{
    if(t[rt].l==t[rt].r)
    {
        t[rt].rx=flag;
        t[rt].idx=id;
        return ;
    }
    if(pos<=t[rt].mid)
        update(pos,id,flag,lson);
    if(pos>t[rt].mid)
        update(pos,id,flag,rson);
    pushup(rt);
}
int query(int p,int flag,int rt)        //注意这里的查询要尽可能的保证选靠左的满足要求的车
{
    if(t[rt].rx<flag)
        return -1;
    if(t[rt].l==t[rt].r)
        return t[rt].idx;
    int ans=-1;
    if(p<=t[rt].mid)    //如果左儿子有解的话就返回左儿子的解
    {
        ans=query(p,flag,lson);
        if(ans>0)
            return ans;
    }
    return query(p,flag,rson);  //否则查询右儿子
}
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+m;i++)
    {
        scanf("%d%d%d",&g[i].l,&g[i].r,&g[i].t);
        g[i].id=i;
        v.pb(g[i].t);
    }
    sort(v.begin(),v.end());    //排序去重
    v.erase(unique(v.begin(),v.end()),v.end());
    build(1,(int)v.size(),1);
    sort(g+1,g+1+m+n);
    for(int i=1;i<=n+m;i++)
    {
        int pos=getid(g[i].t);
        if(g[i].id<=n)  //车
            update(pos,g[i].id,g[i].r,1);
        else        //人
            ans[g[i].id-n]=query(pos,g[i].r,1);
    }
    for(int i=1;i<=m;i++)
    {
        printf("%d",ans[i]);
        if(i!=m)
            printf(" ");
    }
    printf("\n");
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值