• ACM学习历程——NOJ1113 Game I(贪心 || 线段树)


    Description

    尼克发明了这样一个游戏:在一个坐标轴上,有一些圆,这些圆的圆心都在x轴上,现在给定一个x轴上的点,保证该点没有在这些圆内(以及圆上),尼克可以以这个点为圆心做任意大小的圆,他想知道自己做多可以与多少个给定的圆相交(相切也算,包含不算)。

    Input

    输入有多组数据 输入到文件尾

    每一组数据有一个整数n(1<=n<=100000),表示总共有n个圆。

    接下是n行,每行两个整数xi,ri表示该圆的圆心坐标和半径。

    接下来一行为一个整数x,表示尼克选取点的位置。

    x xi的范围[-10^9,10^9]  ri的范围[1,10^9]

    总共有最多10组数据。

    Output

    每组数据输出一行,表示尼克最多可以覆盖多少个圆。

    Sample Input

    2
    1 2
    2 1
    4

    Sample Output

    2

     这个题目条件转换一下就是满足|r-d| <= R <= r+d的R就能与r半径的圆相交,其中d是两圆圆心的距离。

    这样就变成了区间增值,然后查询区间中的最大值。

    首先想到的是线段树,复杂度是O(2n*log(2n))。不过由于半径范围的值是离散的,所以采用map进行映射,使其连续。不过AC用时500ms左右。

    然后发现其实直接处理后直接贪心就行。将所有区间的左右端点排序,排序时需要保存标记,用于记录这个端点是某个区间的左端点还是右端点。然后就是扫一遍,对于是左端点的自然值加一,对于右端点的自然值减一,然后贪心过程中的最大值。AC用时85ms左右。


    贪心代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <map>
    #include <set>
    #include <algorithm>
    #define LL long long
    
    using namespace std;
    
    struct node
    {
        LL index;
        bool isleft;
    }ind[200005];
    
    int n, ans;
    LL x[100005], r[100005], xx;
    
    bool cmp(node a, node b)
    {
        return a.index < b.index;
    }
    
    LL Abs(LL aa)
    {
        if (aa < 0)
            return -aa;
        else
            return aa;
    }
    
    void Init()
    {
        LL d, Left, Right;
        for (int i = 0; i < n; ++i)
        {
            d = Abs(x[i]-xx);
            Left = Abs(r[i]-d);
            Right = r[i]+d;
            ind[i<<1].index = Left;
            ind[i<<1].isleft = true;
            ind[i<<1|1].index = Right;
            ind[i<<1|1].isleft = false;
        }
        sort(ind, ind+2*n, cmp);
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        while (scanf("%d", &n) != EOF)
        {
            for (int i = 0; i < n; ++i)
            {
                scanf("%lld%lld", &x[i], &r[i]);
            }
            scanf("%lld", &xx);
            Init();
            int len = 2*n;
            int now = 0;
            ans = 0;
            for (int i = 0; i < len; ++i)
            {
                if (ind[i].isleft)
                    now++;
                else
                    now--;
                ans = max(ans, now);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }

    线段树代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <map>
    #include <set>
    #include <algorithm>
    #define LL long long
    
    using namespace std;
    
    //线段树
    //区间每点增值,求区间最值
    const int maxn = 100005;
    struct node
    {
        int lt, rt;
        int val, add;
    }tree[8*maxn];
    
    //向下更新
    void PushDown(int id)
    {
        if (tree[id].add != 0)
        {
            tree[id<<1].add += tree[id].add;
            tree[id<<1].val += tree[id].add;
            tree[id<<1|1].add += tree[id].add;
            tree[id<<1|1].val += tree[id].add;
            tree[id].add = 0;
        }
    }
    
    //向上更新
    void PushUp(int id)
    {
        tree[id].val = max(tree[id<<1].val, tree[id<<1|1].val);
    }
    
    //建立线段树
    void Build(int lt, int rt, int id)
    {
        tree[id].lt = lt;
        tree[id].rt = rt;
        tree[id].val = 0;//每段的初值,根据题目要求
        tree[id].add = 0;
        if (lt == rt)
        {
            //tree[id].add = ??;
            return;
        }
        int mid = (lt + rt) >> 1;
        Build(lt, mid, id<<1);
        Build(mid+1, rt, id<<1|1);
        //PushUp(id);
    }
    
    //增加区间内每个点固定的值
    void Add(int lt, int rt, int id, int pls)
    {
        if (lt <= tree[id].lt && rt >= tree[id].rt)
        {
            tree[id].add += pls;
            tree[id].val += pls;
            return;
        }
        PushDown(id);
        int mid = (tree[id].lt + tree[id].rt) >> 1;
        if (lt <= mid)
            Add(lt, rt, id<<1, pls);
        if (rt > mid)
            Add(lt, rt, id<<1|1, pls);
        PushUp(id);
    }
    
    //查询某段区间内的zuizhi
    int Query(int lt, int rt, int id)
    {
        if (lt <= tree[id].lt && rt >= tree[id].rt)
            return tree[id].val;
        PushDown(id);
        int mid = (tree[id].lt + tree[id].rt) >> 1;
        if (rt <= mid)
            return Query(lt, rt, id<<1);
        if (lt > mid)
            return Query(lt, rt, id<<1|1);
        return max(Query(lt, rt, id<<1), Query(lt, rt, id<<1|1));
    }
    
    
    int n, cnt;
    LL x[100005], r[100005], ind[200005], xx;
    LL Left[100005], Right[100005];
    map <LL, int> id;
    
    bool cmp(LL a, LL b)
    {
        return a < b;
    }
    
    LL Abs(LL aa)
    {
        if (aa < 0)
            return -aa;
        else
            return aa;
    }
    
    void Init()
    {
        id.clear();
        LL d;
        for (int i = 0; i < n; ++i)
        {
            d = Abs(x[i]-xx);
            Left[i] = Abs(r[i]-d);
            Right[i] = r[i]+d;
            ind[i<<1] = Left[i];
            ind[i<<1|1] = Right[i];
        }
        sort(ind, ind+2*n, cmp);
        int len = 2*n;
        cnt = 1;
        for (int i = 0; i < len; ++i)
        {
            if (i == 0)
            {
                id[ind[0]] = 1;
                continue;
            }
            if (ind[i] != ind[i-1])
            {
                id[ind[i]] = ++cnt;
            }
        }
        Build(1, cnt, 1);
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        while (scanf("%d", &n) != EOF)
        {
            for (int i = 0; i < n; ++i)
            {
                scanf("%lld%lld", &x[i], &r[i]);
            }
            scanf("%lld", &xx);
            Init();
            for (int i = 0; i < n; ++i)
            {
                Add(id[Left[i]], id[Right[i]], 1, 1);
            }
            printf("%d
    ", Query(1, cnt, 1));
        }
        return 0;
    }
  • 相关阅读:
    软件设计师经验分享
    数据库设计基本规范
    UEditor上传文件的默认地址修改
    mongoDB简单介绍及安装
    链表中倒数第k个结点
    一入python深似海--对象的属性
    stl--vector 操作实现
    android5.x加入sim1,sim2标识
    leetCode 27.Remove Element (删除元素) 解题思路和方法
    java8新增特性(一)---Lambda表达式
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4463613.html
走看看 - 开发者的网上家园