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);
    }
    
  • 相关阅读:
    全国大学生信息安全竞赛—创新实践能力赛 华东北赛区部分wp
    全国大学生信息安全竞赛—创新实践能力赛初赛部分wp
    XMan冬令营 哈尔滨 day3 移动恶意应用分析
    XMan冬令营 哈尔滨 day2 安卓应用程序逆向分析
    XMan冬令营 哈尔滨 day1 移动应用程序渗透测试
    Linux大作业
    c++ 手写计算器
    KMP字符匹配算法
    二叉树遍历的几种实现
    Jmeter之CSS选择器/JQuery选择器关联
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6892700.html
Copyright © 2011-2022 走看看