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;
}
时间: 2024-09-29 21:10:25

ACM学习历程——NOJ1113 Game I(贪心 || 线段树)的相关文章

ACM学习历程——HDU3333 Turing Tree(线段树 &amp;&amp; 离线操作)

Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems about intervals, because Turing Tree could easily have the solution. As well, wily 3xian made lots of new problems about intervals. So, today, this sick t

ACM学习历程—POJ1151 Atlantis(扫描线 &amp;&amp; 线段树)

Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend

ACM学习历程—HihoCoder1309任务分配(排序 &amp;&amp; 贪心)

http://hihocoder.com/problemset/problem/1309 题目大意是给定n个任务的起始时间,求问最少需要多少台机器. 有一个贪心的策略就是,如果说对于一个任务结束,必然接一个开始时间最接近这个的比较合算.我们假想一个任务池,那么任务池中最早结束的那个,必然接剩余任务中最早开始的比赛合算(相同开始时间最早结束),而且假设这个任务是P,那么对于一个结束时间晚于P的任务,显然后面的一段时间是浪费的,同样对于一个开始时间晚于P的任务,前面一段是浪费的: 关键在于某个开始时

ACM学习历程—HDU 4287 Intelligent IME(字典树 || map)

Description We all use cell phone today. And we must be familiar with the intelligent English input method on the cell phone. To be specific, the number buttons may correspond to some English letters respectively, as shown below: 2 : a, b, c    3 : d

ACM学习历程—HDU2222 Keywords Search(字典树)

Keywords Search Description In the modern time, Search engine came into the life of everybody like Google, Baidu, etc.       Wiskey also wants to bring this feature to his image retrieval system.       Every image have a long description, when users

ACM学习历程—SNNUOJ 1239 Counting Star Time(树状数组 &amp;&amp; 动态规划 &amp;&amp; 数论)

http://219.244.176.199/JudgeOnline/problem.php?id=1239 这是这次陕西省赛的G题,题目大意是一个n*n的点阵,点坐标从(1, 1)到(n, n),每个点都有权值,然后从(x, y)引x轴的垂线,然后构成一个三角形,三个顶点分别是(0, 0),(x, 0)和(x, y).求三角形内点的权值和,包括边界,n的范围是1000,m的范围是100000,说起来也比较坑..学弟n*m的复杂度竟然水过去了,目测比赛数据比较水..不过我挂到我们OJ上给了一组随

ACM学习历程—HDU 4726 Kia&#39;s Calculation( 贪心&amp;&amp;计数排序)

DescriptionDoctor Ghee is teaching Kia how to calculate the sum of two integers. But Kia is so careless and alway forget to carry a number when the sum of two digits exceeds 9. For example, when she calculates 4567+5789, she will get 9246, and for 12

ACM学习历程—HDU 5023 A Corrupt Mayor&#39;s Performance Art(广州赛区网赛)(线段树)

Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this seemed a safe way for mayor X to make money. Becaus

ACM学习历程—UESTC 1226 Huatuo&#39;s Medicine(数学)(2015CCPC L)

题目链接:http://acm.uestc.edu.cn/#/problem/show/1226 题目就是构造一个对称的串,除了中间的那个只有1个,其余的两边都是对称的两个,自然答案就是2*n-1. 代码: #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #