zoukankan      html  css  js  c++  java
  • BZOJ 4561 [JLoi2016]圆的异或并 ——扫描线

    扫描线的应用。

    扫描线就是用数据结构维护一个相对的顺序不变,带修改的东西。

    通常只用于一次询问的情况。

    抽象的看做一条垂直于x轴直线从左向右扫过去。

    这道题目要求求出所有圆的异或并。

    所以我们可以求出每一个圆的系数,然后乘上他们的面积。

    由于不会出现相交的情况,所以圆弧的相对顺序是不变的。

    所以我们用扫描线加入的时候,讨论一下上面的圆弧分别是上下半圆的情况。

    然后比较容易的得出结论。

    如果是上半圆,这个圆就属于它。

    如果是下半弧,那么和它的包含性相同。

    接下来找到它的父亲就可以了。

    然后用set来维护这条扫描线,比较函数是计算交点的。

    然后需要注意一下精度的处理,以及排序的时候第一关键字和第二关键字。

    最后计算答案即可。

    #include <set>
    #include <map>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    #define ll long long
    #define maxn 200005
     
    ll n,top=0,cal[maxn],T;
     
    struct Circle{
        ll x,y,r;
        Circle (){}
        Circle (ll _x,ll _y,ll _r) {x=_x;y=_y;r=_r;}
        void read(){scanf("%lld%lld%lld",&x,&y,&r);}
    }a[maxn];
     
    struct Events{
        ll id,d;
        Events(){}
        Events(ll _id,ll _d){id=_id;d=_d;}
        void print()
        {
            printf("By Circle %lld Do %lld
    ",id,d);
        }
    }b[maxn<<1];
     
    #define eps 1e-8
     
    int fcmp(double a)
    {
        return a<-eps?-1:a>eps;
    }
     
    struct Node{
        ll x,y,r,tag,id;
        Node () {}
        Node (ll _x,ll _y,ll _r,ll _tag,ll _id) {x=_x;y=_y;r=_r;tag=_tag;id=_id;}
        void print()
        {
            printf("At ( %lld, %lld, %lld) Tag %lld
    ",x,y,r,tag);
        }
        bool operator < (const Node & b) const{
            double ya,yb;
            ya=1.0*r*r-1.0*(T-x)*(T-x);
            ya=1.0*y+1.0*tag*sqrt(ya);
            yb=1.0*b.r*b.r-1.0*(T-b.x)*(T-b.x);
            yb=1.0*b.y+1.0*b.tag*sqrt(yb);
            return fcmp(ya-yb)==0?tag<b.tag:fcmp(ya-yb)<0;
        }
    };
     
    set <Node> s;
     
    bool cmpb(Events first,Events second)
    {
        ll lf=a[first.id].x-a[first.id].r*first.d,ls=a[second.id].x-a[second.id].r*second.d;
        return lf==ls?first.d==second.d?a[first.id].y<a[second.id].y:first.d<second.d:lf<ls;
    }
     
    void Add(int id,int d)
    {
        Node P;
        if (d==1)
        {
            P=Node(a[id].x,a[id].y,a[id].r,1,id); s.insert(P);
            P=Node(a[id].x,a[id].y,a[id].r,-1,id);s.insert(P);
        }
        else
        {
            P=Node(a[id].x,a[id].y,a[id].r,1,id); s.erase(P);
            P=Node(a[id].x,a[id].y,a[id].r,-1,id);s.erase(P);
        }
    }
     
    ll query(ll x,ll y)
    {
        T=x;
        Node now=Node(x,y,0,1,1);
        Node pre=(*(s.upper_bound(now)));
        if (pre.tag==1) 
            return -cal[pre.id];
        else
            return cal[pre.id];
    }
     
    int main()
    {
        scanf("%lld",&n);
        F(i,1,n) a[i].read(); a[++n]=Circle(0,0,3e8);
        F(i,1,n) b[++top]=Events(i,1),b[++top]=Events(i,-1);
        sort(b+1,b+top+1,cmpb);
        cal[n]=-1;Add(n,1);
        F(i,2,top-1)
        {
            if (b[i].d==1) cal[b[i].id]=query(a[b[i].id].x-a[b[i].id].r,a[b[i].id].y);
            Add(b[i].id,b[i].d);
        }
        Add(n,-1);
        ll ans=0;
        F(i,1,n-1) ans+=cal[i]*a[i].r*a[i].r;
        printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    28完全背包+扩展欧几里得(包子凑数)
    HDU 3527 SPY
    POJ 3615 Cow Hurdles
    POJ 3620 Avoid The Lakes
    POJ 3036 Honeycomb Walk
    HDU 2352 Verdis Quo
    HDU 2368 Alfredo's Pizza Restaurant
    HDU 2700 Parity
    HDU 3763 CDs
    POJ 3279 Fliptile
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6892700.html
Copyright © 2011-2022 走看看