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\n", 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\n", Query(1, cnt, 1));

    }

    return 0;

}

 

 

你可能感兴趣的:(game)