现在的位置: 首页 > 综合 > 正文

Vijos 1883 月光的魔法(栈)

2019年02月11日 ⁄ 综合 ⁄ 共 1094字 ⁄ 字号 评论关闭

由一些圆心都在x轴上的圆,任意两个圆的关系只会是内含,内切,外切,外离。求圆把平面分成多少个部分。

题目做法据说很多,仅知道其中两种:栈和并查集。

首先对圆进行排序,优先左端点位置,然后是半径长度。然后从左到右扫描一遍。

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
#define MAXN 300100
#define LL long long
#define INF 1000000100

struct Circle
{
    LL l, r, cnt, cap;
    Circle() {}
    Circle(LL _l, LL _r, LL _cnt, LL _cap):
        l(_l), r(_r), cnt(_cnt), cap(_cap){}
    bool operator <(const Circle &argu) const
    {
        if(l == argu.l)
            return argu.r < r;
        else
            return l < argu.l;
    }
    void out()
    {
        printf("%I64d %I64d %I64d %I64d\n", l, r, cnt, cap);
    }
}cc[MAXN];

int n, ctop;
LL x, r;
int s[MAXN];

int main()
{
    //freopen("1883.in", "r", stdin);

    scanf("%d", &n);

    cc[0] = Circle(-INF, (LL)2 * INF, (LL)1, (LL)3 * INF);
    for(int i = 1; i <= n; i++)
    {
        scanf("%I64d%I64d", &x, &r);
        cc[i] = Circle(x - r, x + r, (LL)1, (LL)2 * r);
    }

    n++;
    sort(cc, cc + n);

    ctop = s[0] = 0;
    for(int i = 1; i < n; i++)
    {
        while(cc[i].l >= cc[s[ctop]].r)
        {
            if(cc[s[ctop]].cap == 0)
                cc[s[ctop]].cnt++;
            cc[s[ctop - 1]].cnt += cc[s[ctop]].cnt;
            ctop--;
        }
        cc[s[ctop]].cap -= cc[i].r - cc[i].l;
        s[++ctop] = i;
    }

    while(ctop > 0)
    {
        if(cc[s[ctop]].cap == 0)
            cc[s[ctop]].cnt++;
        cc[s[ctop - 1]].cnt += cc[s[ctop]].cnt;
        ctop--;
    }

    printf("%I64d\n", cc[0].cnt);

    return 0;
}

抱歉!评论已关闭.