当前位置: 代码迷 >> 综合 >> Codeforces Round #111 (Div. 2) E题 Buses and People 线段树+离散化
  详细解决方案

Codeforces Round #111 (Div. 2) E题 Buses and People 线段树+离散化

热度:5   发布时间:2024-01-13 18:07:48.0

这题一看就是离散化加线段树,但是怎么建树确实没想出来。不过看到每个bus的时间点都不同,可能会有一点提示。

后来仿照一个神牛的代码写了一下 。

思路是这样的:首先,将bus和person的起止坐标一并取出到一个数组中,然后离散化之,对每个人每个bus都记录一下id,然后就是把这些坐标排序,去重,数组大小数就是线段树的长度了, 就可以建树了。然后用二分查找把bus和人的起止坐标在数组中的位置找出,记录下来,替换掉原来的坐标,然后将人和bus按照起点坐标从左到右进行结构体排序。  

然后就是线段树的部分,线段树中每个结点存储的信息是一个集合,每个元素是bus的时间和id形成的pair。建树的时候,刚开始每个结点没有bus覆盖,所以时间就是无限大,id也就是-1了。然后按刚才排好序的结构体数组枚举人,对每个人,将出发站点不在人右边的bus的信息插入线段树中,因为只有这样的bus才有可能将人带到目的地,并且,由于bus也是排好序的,所以对于一个人来说,如果他前边的人所能上的bus都插入了,那么他也不用再重复插入这些bus,这样的好处很明显,如果全部插入后进行查询,会造成每个结点的set中元素很多,从而导致超时,因为即使这样优化,最终也接近TLE。而插入的方法很简单,将所有包含bus终点的区间均插入该bus的时间和id即可。

对每个人来说,插入完毕后就进行查询了,查询的区间必然是从这个人要到的地方一直到线段树末尾,然后对任何其子区间中包含的bus时间和id,取最小值即可


总体来说 ,复杂度是n log(n)log(n)级别的

其中多出来的一个log(n)是set的insert和lower_bound函数带来的。



/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define INF 2000000000
#define MAXN 100005
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
int tmp [4 * MAXN], cnt;
int ans[MAXN];
set<pair<int,int> >::iterator it;
struct Bus
{int s, f, t, id;bool operator <(const Bus a) const{return s < a.s;}
}bus[MAXN];
struct Person
{int l, r, b, id;bool operator <(const Person a) const{return l < a.l;}
}p[MAXN];
struct node
{int left, right, mid;set<pair<int, int> >v;
}tree[16 * MAXN];
int bi_search(int v)
{int left = 0, right = cnt - 1;while(left <= right){int mid = (left + right) / 2;if(tmp[mid] >= v) right = mid - 1;else left = mid + 1;}return left;
}
void make_tree(int s, int e, int C)
{tree[C].left = s;tree[C].right = e;tree[C].mid = (s + e) >> 1;tree[C].v.insert(make_pair(INF, -1));if(s == e) return ;make_tree(s, tree[C].mid, L(C));make_tree(tree[C].mid + 1, e, R(C));
}
void update(int p, pair<int, int > v, int C)
{if(tree[C].left <= p && tree[C].right >= p) tree[C].v.insert(v);if(tree[C].left == tree[C].right) return;if(p <= tree[C].mid) update(p, v, L(C));else update(p, v, R(C));
}
pair<int, int > query(int s, int e, int p, int C)
{if(tree[C].left >= s && tree[C].right <= e){it = tree[C].v.lower_bound(make_pair(p, -1));return *it;}pair<int, int > x(INF, -1), y(INF, -1);if(tree[C].mid >= s) x = query(s, e, p, L(C));if(tree[C].mid < e) y = query(s, e, p, R(C));return x.first < y.first ? x : y;
}
int main()
{int n, m;scanf("%d%d", &n, &m);cnt = 0;for(int i = 0; i < n; i++){scanf("%d%d%d", &bus[i].s, &bus[i].f, &bus[i].t);bus[i].id = i + 1;tmp[cnt++] = bus[i].s;tmp[cnt++] = bus[i].f;}for(int i = 0; i < m; i++){scanf("%d%d%d", &p[i].l, &p[i].r, &p[i].b);p[i].id = i + 1;tmp[cnt++] = p[i].l;tmp[cnt++] = p[i].r;}sort(tmp, tmp + cnt);cnt = unique(tmp, tmp + cnt) - tmp;make_tree(0, cnt - 1, 1);for(int i = 0; i < n; i++){bus[i].s = bi_search(bus[i].s);bus[i].f = bi_search(bus[i].f);}for(int i = 0; i < m; i++){p[i].l = bi_search(p[i].l);p[i].r = bi_search(p[i].r);}int pos = 0;sort(bus, bus + n);sort(p, p + m);for(int i = 0; i < m; i++){while(pos < n && bus[pos].s <= p[i].l){update(bus[pos].f, make_pair(bus[pos].t, bus[pos].id), 1);pos++;}pair<int, int> t = query(p[i].r, cnt - 1, p[i].b, 1);ans[p[i].id] = t.second;}for(int i = 1; i <= m; i++){if(i > 1) putchar(' ');printf("%d", ans[i]);}puts("");return 0;
}


  相关解决方案