Loading

Bomas 圆圈树 树上最大独立集 Kattis - bomas

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\n",ans[i] + !ch[i]);
}
posted @ 2021-08-24 11:24  MQFLLY  阅读(146)  评论(0编辑  收藏  举报