• 圆圈游戏 [扫描线, 计算几何]


    圆圈游戏


    color{red}{正解部分}

    将所有圆按照 半径 排序, 对第 ii 个圆, 在 (i,N](i, N] 中找到一个包含 ii 的圆 jj, jjii 连边, 作为 ii 的父亲,
    可以构建出一个森林, 再加一个半径无穷大的圆 N+1N+1, 就是一棵树了 .

    进行 树形 dpdp, 设 F[i]F[i] 表示 前 ii 个圆, ii 这个圆不选所能得到的最大值,
    F[i]=max(F[j],w[j])F[i] = sum max(F[j], w[j]), 状态转移复杂度 O(N)O(N), 建树复杂度 O(N2)O(N^2) .


    考虑怎么优化 寻找父亲 的过程, 把所有圆分为上下两个圆弧,
    上圆弧 xx 坐标取左端点, 下圆弧 xx 坐标取右端点, 按照 xx 坐标进行排序,
    顺序加入 std::set<Hu> 中, 以 过当前的 xx 坐标且平行于 yy 轴的直线 与 圆弧的交点 yy 坐标 递增排序,
    然后就可以在 setset二分 寻找父亲了, 时间复杂度 O(NlogN)O(N log N) .


    color{red}{实现部分}

    为了便于理解, 举个例子 downarrow
    在这里插入图片描述

    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 200005;
    
    int N;
    int L_x;
    int F[maxn];
    int Fa[maxn];
    
    struct circle{ 
            int x, y, r, w;
            double jdzb(int dir){ return y + dir*sqrt(1.0*r*r - (1.0*L_x-x)*(L_x-x)); }
    } A[maxn];
    
    struct Hu{ 
            int dir, id;
            bool operator < (const Hu &b) const{ return id==b.id ? dir<b.dir : (A[id].jdzb(dir) < A[b.id].jdzb(b.dir)); }
    } B[maxn];
    
    bool cmp(Hu a, Hu b){ return A[a.id].x - a.dir*A[a.id].r < A[b.id].x - b.dir*A[b.id].r; }
    
    std::set <Hu> st;
    std::set <Hu>::iterator it;
    
    int main(){
            N = read();
            int Tmp_1 = 0;
            for(reg int i = 1; i <= N; i ++){
                    A[i].x = read(), A[i].y = read(), A[i].r = read(), A[i].w = read();
                    B[++ Tmp_1] = (Hu){1, i}, B[++ Tmp_1] = (Hu){-1, i};
            }
            std::sort(B+1, B+Tmp_1+1, cmp);
            for(reg int i = 1; i <= Tmp_1; i ++){
                    int id = B[i].id, dir = B[i].dir;
                    L_x = A[id].x - dir*A[id].r;
                    if(dir == 1){
                            if(!st.empty()){ 
                                    it = st.upper_bound(B[i]); 
                                    if(it != st.end()) Fa[id] = (it->dir==1)?it->id:Fa[it->id];
                            }
                            st.insert((Hu){1, id}), st.insert((Hu){-1, id});
                    }else{
                            st.erase((Hu){1, id}), st.erase((Hu){-1, id});
                            F[Fa[id]] += std::max(F[id], A[id].w);
                    }
            }
            printf("%d
    ", F[0]);
            return 0;
    }
    
  • 相关阅读:
    Web中的通配符
    EJB版本
    package-info.java
    dynamic web module version
    深入解析和反思携程宕机事件
    Ubuntu 环境下使用cronolog 切割Tomcat日志
    ubuntu环境下cassandra安装配置
    zabbix自定义触发器语法
    zabbix系统邮件告警Python脚本
    Ubuntu14.04下zabbix2.4.5 源码编译安装
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822459.html
Copyright © 2020-2023  润新知