• 洛谷 P3268 [JLOI2016]圆的异或并 扫描线


    之前做过一到类似的,当时没写题解,今天来补上。

    首先我们发现圆没有交,所以两个圆只有包含和相离两种关系。

    我们考虑用扫描线来处理,随着扫描线的推移,和上面的圆的交点 一直都在 和下面的圆的交点的上面,可以用 (set) 来维护相对位置

    怎么确定一个圆应该是加还是减?我们将圆拆分成上半圆和下半圆,将上半圆插入 (set) 后,找在这扫描线上其下面的那个半圆。

    (1) .若找不到,哪这个圆不会被包含,应该加上

    (2) .若是下半圆,则和那个圆的加减状态相反。

    (3) .若是上半圆,则和那个圆的加减状态相同。

    上面的过程建议画一下图方便理解

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<set>
    #define DB double
    using namespace std;
    int n, tot, now;
    long long ans;
    DB nowx;
    const int N = 200010;
    const DB eps = 1e-9;
    int val[N];
    DB x[N], y[N], r[N];
    struct cir
    {
    	int opt, id;
    	DB nowy()//求圆和当前扫描线交点的y坐标
    	{
    		return y[id] + (DB)opt * sqrt(r[id] * r[id] - (x[id] - nowx) * (x[id] - nowx) + eps);
    	}
    	friend bool operator <(cir x, cir y) {return x.nowy() < y.nowy();}
    };
    set<cir>s;
    set<cir>::iterator it;
    struct xian
    {
    	int opt, x, id;
    	friend bool operator <(const xian &x, const xian &y) {return x.x < y.x;}
    } li[N << 1];
    int main()
    {
    	cin >> n;
    	for (int i = 1; i <= n; ++i)
    	{
    		scanf("%lf%lf%lf", &x[i], &y[i], &r[i]);
    		li[++tot] = (xian) {1, (int)(x[i] - r[i]), i};
    		li[++tot] = (xian) {0, (int)(x[i] + r[i]), i};
    	}
    	sort(li + 1, li + 1 + tot);
    	for (int i = 1; i <= tot; ++i)
    	{
    		nowx = li[i].x;
    		if (li[i].opt)
    		{
    			now = li[i].id; it = s.insert((cir) {1, now}).first;
    			if (it == s.begin())val[now] = 1;
    			else
    			{
    				--it;
    				if ((*it).opt == -1)val[now] = val[(*it).id] ^ 1;
    				else val[now] = val[(*it).id];
    			}
    			s.insert((cir) { -1, now});
    			if (val[now])ans += r[now] * r[now];
    			else ans -= r[now] * r[now];
    		}
    		else s.erase((cir) {1, li[i].id}), s.erase((cir) { -1, li[i].id});
    	}
    	cout << ans;
    	return 0;
    }
    
  • 相关阅读:
    (转)Linux端口nmap和netstat命令
    (转)Linux下增加交换分区的大小
    (转)centos7安装telnet服务
    (转)VmWare下安装CentOS7图文安装教程
    (转)Linux系统安装时分区的选择
    (转)硬盘分区备忘(主分区,扩展分区和逻辑分区)以及Linux硬盘分区工具parted 介绍
    (转).tar.gz文件和.rpm文件的区别
    (转)Linux(Centos)之安装Java JDK及注意事项
    ibatis中integer类型
    ibatis时间比较大小
  • 原文地址:https://www.cnblogs.com/wljss/p/12658663.html
Copyright © 2020-2023  润新知