圆 圈 游 戏 圆圈游戏 圆圈游戏
正 解 部 分 \color{red}{正解部分} 正解部分
将所有圆按照 半径 排序, 对第
i
i
i 个圆, 在
(
i
,
N
]
(i, N]
(i,N] 中找到一个包含
i
i
i 的圆
j
j
j,
j
j
j 向
i
i
i 连边, 作为
i
i
i 的父亲,
可以构建出一个森林, 再加一个半径无穷大的圆
N
+
1
N+1
N+1, 就是一棵树了 .
进行 树形
d
p
dp
dp, 设
F
[
i
]
F[i]
F[i] 表示 前
i
i
i 个圆,
i
i
i 这个圆不选所能得到的最大值,
F
[
i
]
=
∑
max
(
F
[
j
]
,
w
[
j
]
)
F[i] = \sum \max(F[j], w[j])
F[i]=∑max(F[j],w[j]), 状态转移复杂度
O
(
N
)
O(N)
O(N), 建树复杂度
O
(
N
2
)
O(N^2)
O(N2) .
考虑怎么优化 寻找父亲 的过程, 把所有圆分为上下两个圆弧,
上圆弧
x
x
x 坐标取左端点, 下圆弧
x
x
x 坐标取右端点, 按照
x
x
x 坐标进行排序,
顺序加入 std::set<Hu>
中, 以 过当前的
x
x
x 坐标且平行于
y
y
y 轴的直线 与 圆弧的交点
y
y
y 坐标 递增排序,
然后就可以在
s
e
t
set
set 中 二分 寻找父亲了, 时间复杂度
O
(
N
log
N
)
O(N \log N)
O(NlogN) .
实 现 部 分 \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\n", F[0]);
return 0;
}