zoukankan      html  css  js  c++  java
  • 圆圈游戏 [扫描线, 计算几何]

    圆圈游戏


    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;
    }
    
  • 相关阅读:
    JZOJ 3034. 【NOIP2012模拟10.17】独立集
    JZOJ 3035. 【NOIP2012模拟10.17】铁轨
    JZOJ 1259. 牛棚安排
    数位DP JZOJ 3316. 非回文数字
    JZOJ 3046. 游戏
    JZOJ 3013. 填充棋盘
    debian 安装oracle提供的java8
    java 汉字转拼音 PinYin4j
    debian ssh设置root权限登陆 Permission denied, please try again
    java并发下订单生成策略
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822459.html
Copyright © 2011-2022 走看看