【题解】Berland.Taxi Codeforces 883L 模拟 线段树 堆

Prelude

题目传送门:ヾ(?ω?`)o


Solution

按照题意模拟即可。

维护一个优先队列,里面装的是正在运营中的出租车,关键字是乘客的下车时间。

维护一个线段树,第\(i\)个位置表示第\(i\)个房子前面有没有停放出租车,这样在有人需要打车的时候可以快速找到离她最近的车的位置。

对每个房子维护一个堆,里面装的是停在这个房子前面的出租车,关键字是出租车的编号和上一个乘客下车的时间,上一个乘客下车越早,等待时间越长。

然后模拟时间的流逝就可以了,代码非常好写。


Code

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <utility>
#include <cstdlib>
#include <cassert>

using namespace std;
typedef long long ll;
const int MAXN = 200010;
const int INF = 0x3f3f3f3f;
int _w;

int n, k, m, x[MAXN], a[MAXN], b[MAXN];
ll t[MAXN];

namespace SGT {
    int sumv[MAXN<<2], ql, qr, qv;
    void _add( int o, int L, int R ) {
        sumv[o] += qv;
        if( L == R ) return;
        int M = (L+R)/2, lc = o<<1, rc = lc|1;
        if( ql <= M ) _add(lc, L, M);
        else _add(rc, M+1, R);
    }
    void add( int p, int v ) {
        ql = p, qv = v;
        _add(1, 1, n);
    }
    void _queryl( int o, int L, int R ) {
        if( L >= ql && R <= qr ) {
            if( !sumv[o] ) return;
            while( L != R ) {
                int M = (L+R)/2, lc = o<<1, rc = lc|1;
                if( sumv[lc] ) o = lc, R = M;
                else o = rc, L = M+1;
            }
            qv = L;
        } else {
            int M = (L+R)/2, lc = o<<1, rc = lc|1;
            if( ql <= M && !qv ) _queryl(lc, L, M);
            if( qr > M && !qv ) _queryl(rc, M+1, R);
        }
    }
    int queryl( int l, int r ) {
        ql = l, qr = r, qv = 0;
        _queryl(1, 1, n);
        return qv;
    }
    void _queryr( int o, int L, int R ) {
        if( L >= ql && R <= qr ) {
            if( !sumv[o] ) return;
            while( L < R ) {
                int M = (L+R)/2, lc = o<<1, rc = lc|1;
                if( sumv[rc] ) o = rc, L = M+1;
                else o = lc, R = M;
            }
            qv = L;
        } else {
            int M = (L+R)/2, lc = o<<1, rc = lc|1;
            if( qr > M && !qv ) _queryr(rc, M+1, R);
            if( ql <= M && !qv ) _queryr(lc, L, M);
        }
    }
    int queryr( int l, int r ) {
        ql = l, qr = r, qv = 0;
        _queryr(1, 1, n);
        return qv;
    }
}

struct Node {
    ll t;
    int id;
    Node() {}
    Node( ll t, int id ):
        t(t), id(id) {}
    bool operator<( const Node &rhs ) const {
        return t == rhs.t ? id > rhs.id : t > rhs.t;
    }
};
priority_queue<Node> pq[MAXN], evt;

void prelude() {
    for( int i = 1; i <= k; ++i ) {
        pq[x[i]].push( Node(0, i) );
        SGT::add(x[i], 1);
    }
}

void run( ll t ) {
    while( !evt.empty() && evt.top().t <= t ) {
        Node car = evt.top(); evt.pop();
        SGT::add(x[car.id], 1);
        // printf( "car.id = %d, x[id] = %d\n", car.id, x[car.id] );
        pq[x[car.id]].push(car);
    }
}
int use( int pos ) {
    Node car = pq[pos].top(); pq[pos].pop();
    SGT::add(pos, -1);
    return car.id;
}
int freecar( int pos ) {
    if( !SGT::sumv[1] ) return 0;
    int left = SGT::queryr(1, pos);
    int right = SGT::queryl(pos, n);
    // printf( "left = %d, right = %d\n", left, right );
    if( !left ) left = -INF;
    if( !right ) right = INF;
    if( left == right ) {
        return use(left);
    } else if( pos-left < right-pos ) {
        return use(left);
    } else if( right-pos < pos-left ) {
        return use(right);
    } else {
        Node cl = pq[left].top(), cr = pq[right].top();
        if( cl.t == cr.t ) {
            if( cl.id < cr.id ) {
                return use(left);
            } else {
                return use(right);
            }
        } else if( cl.t < cr.t ) {
            return use(left);
        } else {
            return use(right);
        }
    }
}
void solve() {
    ll now = 0;
    for( int i = 0; i < m; ++i ) {
        now = max(now, t[i]);
        run(now);
        int car = freecar( a[i] );
        // printf( "now = %lld, car = %d\n", now, car );
        if( !car ) {
            now = max(now, evt.top().t);
            run(now);
            // printf( "now = %lld, car = %d\n", now, car );
            car = freecar( a[i] );
        }
        // printf( "now = %lld, car = %d\n", now, car );
        printf( "%d %lld\n", car, now - t[i] + abs(x[car] - a[i]) );
        evt.push( Node(now + abs(x[car] - a[i]) + abs(a[i] - b[i]), car) );
        x[car] = b[i];
    }
}

int main() {
    _w = scanf( "%d%d%d", &n, &k, &m );
    for( int i = 1; i <= k; ++i )
        _w = scanf( "%d", x+i );
    for( int i = 0; i < m; ++i )
        _w = scanf( "%lld%d%d", t+i, a+i, b+i );
    prelude(), solve();
    return 0;
}
时间: 2024-08-12 07:42:02

【题解】Berland.Taxi Codeforces 883L 模拟 线段树 堆的相关文章

CodeForces 46DParking Lot线段树

#include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set> #include <qu

Codeforces 19D Points 线段树+set

题目链接:点击打开链接 线段树维护y值大于val的最小x值 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <iostream> #include <map> #include <set> #include <math.h> using namespace std; #define inf

Codeforces 444C(线段树)

区间颜色不一致就更新到底,否则lazy标记 #include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; #define lc l,m,index<<1 #define rc m+1,r,index<<1|1 #define N 100005 #define ll __int64 struct node { bool sa

New Year and Old Subsequence CodeForces - 750E(线段树 + 矩阵)

New Year and Old Subsequence (CodeForces - 750E) 题意: 给出一个长度为\(N\)的数字串,\(q\)次询问.每次询问一段区间.在区间内删除尽量少的字符,使得区间内含有序列"\(2017\)",且不含有"\(2016\)". \(n,q<=200000\). 题解: 用\(01234\)五种状态分别表示"". "\(2\)"."\(20\)"."

Sum Queries? CodeForces - 1217E (线段树)

Sum Queries? CodeForces - 1217E (线段树) 题意: 定义一个集合为\(balanced\)的,当且仅当集合内数字之和的每个十进制位,都与集合中某个数该位相同.否则,称该集合为\(unbalanced\)的. 给定一个长度为\(n\)的序列,\(q\)次询问一个区间内数字之和最小的\(unbalanced\)集合,输出数字之和.若没有输出\(-1\). \(n,q<=200000\). 题解: 可以发现,如果存在\(unbalanced\)集合,那么最小的一定是只两

ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(模拟+线段树)

https://nanti.jisuanke.com/t/30996 题意 每天增加m个灯泡,n个房间,能一次性换就换,模拟换灯泡过程.询问第几天的状态 分析 离线做,按题意模拟.比赛时线段树写挫了..导致不断超时,我太弱了.每次询问符合要求的最左边的点. #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #i

Codeforces 787D. Legacy 线段树优化建图+最短路

output standard output Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them. There are n planets in their universe numbered from 1 to n.

CodeForces - 1263E(线段树维护前缀和最值)

题意 https://vjudge.net/problem/CodeForces-1263E 您要设计一个只有一行的打字机,这一行的长度是无限大,一开始可以认为每个字符都是空.您的打字机有一个光标只指向一个字符,一开始指向最左侧的字符. 使用者有三种操作: L 将光标向左移一格(当光标已经在最左侧时,忽略这次操作) R 将光标向右移一格 一个小写字符或者'(',')' 将当前字符替换为给定字符 您需要在每次操作后,判断这一行是否是合法括号序列(例如 (ahakioi) 就是合法的,(ige))(

G - Greg and Array CodeForces - 296C 差分+线段树

题目大意:输入n,m,k.n个数,m个区间更新标记为1~m.n次操作,每次操作有两个数x,y表示执行第x~y个区间更新. 题解:通过差分来表示某个区间更新操作执行的次数.然后用线段树来更新区间. #include<bits/stdc++.h> using namespace std; const int N=1E5+7; typedef long long ll; ll arr[N]; ll tt[N],cnt[N]; struct stu{ ll value,add; }tree[N+N+N