Bomas 圆圈树 树上最大独立集 Kattis - bomas
题意
给出若干个互不相交的(可以包含)的圆形 位置和半径
给出(q)个独立的询问,每次询问给出一个圆,求这个圆内 能够选择的圆圈数量,能够选择的限制是这些圆形互不相邻。
[1 leq n,q leq 1e5\
-1e7 leq x_i,y_i leq 1e7\
1 leq r leq 1e7
]
分析
对于互不相交的圆可以构造出一颗树(类似括号序列)
建树方法就是把每个圆拆成上下半圆,用一个扫描线扫描(x)轴,因为互不相交,因此可以插入到一颗平衡树中,将上半圆看成插入操作,下半圆看成删除操作,插入时,可以二分查找(x)轴上第一个(y)大于等于当前y的点,如果这个点对应的是上半圆,则是父亲关系,否则是兄弟关系。如果遇到的是删除操作,就直接把上下半圆从平衡树中删除即可。
容易发现,建树以后就变成了树上最大独立集问题
代码
#include<bits/stdc++.h>
#define pii pair<ll,ll>
#define fi first
#define se second
#define eps 1e-3
#define equals(a,b) fabs(a - b) < eps
using namespace std;
typedef long long ll;
inline ll rd(){
ll x;
scanf("%lld",&x);
return x;
}
const int maxn = 4e5 + 5;
const int MOD = 998244353;
inline int mul(int a,int b){
return (ll)a * b % MOD;
}
inline void add(int &a,int b){
a += b;
if(a >= MOD) a -= MOD;
}
inline int ksm(int a,int b = MOD - 2,int m = MOD){
int ans = 1;
int base = a;
while(b){
if(b & 1) ans = mul(ans,base);
base = mul(base,base);
b >>= 1;
}
return ans;
}
struct cir{
ll x,y,r;
cir(){}
cir(ll _x,ll _y,ll _r){x = _x;y = _y;r = _r;}
}c[maxn];
ll Lx;
inline ll cal(ll x){return x * x;}
struct ins{
int x,opt,id;
ins(){}
ins(int _x,int _opt,int _id){x = _x;opt = _opt;id = _id;}
friend bool operator < (const ins &a,const ins &b){
double Y1 = c[a.id].y + a.opt * sqrt(cal(c[a.id].r) - cal(c[a.id].x - Lx));
double Y2 = c[b.id].y + b.opt * sqrt(cal(c[b.id].r) - cal(c[b.id].x - Lx));
if(equals(Y1,Y2)) return a.opt < b.opt;
return Y1 < Y2;
}
}w[maxn << 1];
inline bool cmp(ins &a,ins &b){
return a.x < b.x;
}
vector<int> e[maxn];
int fa[maxn];
int ans[maxn];
bool ch[maxn];
int n,m;
void dfs(int u){
if(e[u].empty()){
if(u > n){
ch[u] = 0;
ans[u] = 0;
}
else {
ch[u] = 1;
ans[u] = 1;
}
}
else {
ch[u] = 1;
for(auto v:e[u]){
dfs(v);
ans[u] += ans[v];
if(ch[v]) ch[u] = 0;
}
if(u <= n) ans[u] += ch[u];
if(u > n) ch[u] ^= 1;
}
}
int main(){
n = rd();
m = rd();
int N = n + m;
for(int i = 1;i <= N;i++){
ll x = rd();
ll y = rd();
ll r = rd();
c[i] = cir(x,y,r);
w[(i << 1) - 1] = ins(c[i].x - c[i].r,1,i);
w[i << 1] = ins(c[i].x + c[i].r,-1,i);
}
set<ins> s;
sort(w + 1,w + (N << 1) + 1,cmp);
for(int i = 1;i <= (N << 1);i++){
Lx = w[i].x;
if(w[i].opt == 1) {
auto it = s.upper_bound(ins(0,1,w[i].id));
if(it == s.end()) {
e[0].push_back(w[i].id);
fa[w[i].id] = 0;
}
else{
if(it -> opt == -1) {
e[fa[it -> id]].push_back(w[i].id);
fa[w[i].id] = fa[it -> id];
}
else {
e[it -> id].push_back(w[i].id);
fa[w[i].id] = it -> id;
}
}
s.insert(ins(0,1,w[i].id));
s.insert(ins(0,-1,w[i].id));
}
else{
s.erase(ins(0,1,w[i].id));
s.erase(ins(0,-1,w[i].id));
}
}
dfs(0);
for(int i = n + 1;i <= N;i++)
printf("%d
",ans[i] + !ch[i]);
}