`
java-mans
  • 浏览: 11415483 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

这题一看就是离散化加线段树,但是怎么建树确实没想出来。不过看到每个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;
}


分享到:
评论

相关推荐

    Codeforces Round #723 (Div. 2).md

    Codeforces Round #723 (Div. 2).md

    Codeforces Round #630 (Div. 2) D. Walk on Matrix(构造)

    上面代码跑出来的dp[n][m]是0,然后从(1,1)(1,2)(2,2)(2,3)这样的相与值是k (看懂ans+k是啥应该就懂了) 代码: int main() { std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int ans=(1&...

    Codeforces Round #627 (Div. 3) C. Frog Jumps(思维)

    传送门 题意: 开始位置在0,问能否跳到n+1位置 每步只能跳d 在1——n每个位置有方向,L,R,求d的最小值 思路: 只用找相邻两个R之间的最大值即可 代码: #include #include ...typedef long long l

    Codeforces Round #627 (Div. 3) B. Yet Another Palindrome Problem

    就是把所有相等的数放到一个vector里,如果他出现大于2次,看最远的间距是否大于2即可,找到一个就可以 代码: #include #include #include #include #include #include #include #include #include #include #...

    Codeforces Round #629 (Div. 3) B. K-th Beautiful String

    长度为n的字符串包含n−2n−2n−2个aaa和222个bbb,求按照字典序排列输出第kkk个字符串 解题思路 第一个bbb在倒数第二位有1个字符串,在倒数第三位有2个字符串…在倒数第nnn位时有n−1n-1n−1个字符串 可以根据第一...

    Codeforces Round #479 (Div. 3) E. Cyclic Components

    E. Cyclic Components 题目链接-E. Cyclic Components 题目大意 给你nnn个点和mmm条边,求所构成图中单圈环的个数 解题思路 并查集并查集并查集 很明显单圈环每个点的度都为222,所以我们可以用数组cnt[]记录每...

    Codeforces Round #629 (Div. 3) E.Tree Queries (DFS)

    Codeforces Round #629 (Div. 3) E.Tree Queries (DFS) 思路:若ai 在路径上 ,则ai的父结点一定在路径上,若ai是路径上某个结点的子结点,则ai的父结点一定在路径上,综上只需考虑ai的父节点就行了。对每个ai判断...

    Codeforces Round #628 (Div. 2) A. EhAb AnD gCd

    输入一个正整数x,找出这样的2个正整数a和b,使得gcd(a,b)+lcm(a,b)=x 解题思路 找最特殊的情况a=1,b=x-1即可 这样a,b两个数最大公因数为1,最小公倍数x-1,满足题意√ 附上代码 #include #define int long long #...

    Codeforces Round #635 (Div. 2)D. Xenia and Colorful Gems

    其实这道题比较水,但当时思路错,一心想着化简公式,浪费了好多时间a.a 题意:三个数组,求(x-y)(x-y)+(x-z)(x-z)+(y-z)*(y-z)的最小值 题解:6nlogn,先sort三个数组a,b,c, 六次枚举二分查找,再每次min找最小值,...

    Codeforces Round #628 (Div.2) C.Ehab and Path-etic MEXs(树,思维)

    传送门 题意: 给一颗n个结点的数,然后n-1条边,我们要做的...如果不是一条链,那肯定有个结点的度大于等于3,把这个结点周围的三条边分别给值0,1,2,这样所有MEX(u,v)最大值为2,因为不可能有一条边同时经过0,1,2这三

    Codeforces Round #628 (Div. 2)

    Ehab and Path-etic MEXs 题意 给两两节点放一个数字(0~n-2 唯一) 给你一棵树,求所有任意两节点相连的路以外的路上的数字的最小值最小 思路 构造 若一个点连了三条边及以上,则这个点的边从最小值开始赋值。其他...

    Codeforces Round #620 (Div. 2) Longest Palindrome

    B. Longest Palindrome time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard output Returning back to problem solving, Gildong is now studying about ...

    Codeforces Round #627 (Div. 3) A. Yet Another Tetris Problem

    给一个长度为n的数组,两种操作,一个是把任意一个ai变成ai+2a_i变成a_i+2ai​变成ai​+2,另一个是如果所有数都大于0,可以把所有数减1,问通过这些操作能否把所有数变为0 思路: 如果任意两个数之差为奇数,那么就...

    Codeforces Round #628 (Div. 2) A~~D

    A #include using namespace std; typedef long long ll; int main(){ int t; cin&gt;&gt;t; while(t--){ ll x; cin&gt;&gt;x; cout&lt;&lt;1&gt;&gt;t; while(t--){ st.clear(); ll n; cin &gt;&gt;n;... ll re

    Educational Codeforces Round 83 (Rated for Div. 2) D

    C(n-2,i-1)*C(j-1,n-2)*(i-1) __ j: n-1 -&gt; m 我们发现内层循环,每次只是j加一,我们就可以只用一次组合数剩下的用差量表示 对于外层循环同理 只有(i-1) * C(n-2,i-1) i会每次加一。我们也只算一次剩下的用差量...

    Codeforces Round #628 (Div. 2)【A B C D】

    EhAb AnD gCd 直接输出1,n-1即可 #include #include #include #include #include #include #include #include #include #include #define pb push_back #define lb lower_bound #define ub upper_bound #define ...

    Codeforces Round #633 (Div. 2) A. Filling Diamonds(找规律)

    传送门 题意: 找规律,题意就是有多少种方式填充该图形 画两个就发现,输出n即可 代码: #include #include #include #include #include #include #include #include ...#define SZ(x) ((int)(x)

    【Codeforces Round#620 (Div. 2)】B. Longest Palindrome 题解

    题目链接:B. Longest Palindrome 题目 Returning back to problem ... For example, strings “pop”, “noon”, “x”, and “kkkkkk” are palindromes, while strings “moon”, “tv”, and “abab” are not.

Global site tag (gtag.js) - Google Analytics