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

圆圈游戏


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;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822459.html