zoukankan      html  css  js  c++  java
  • Bomas 圆圈树 树上最大独立集 Kattis

    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]);
    }
    
  • 相关阅读:
    JS 对象定义
    JavaScript HTML DOM 元素(节点)
    DOM 事件
    DOM CSS
    DOM HTML
    DOM 简介
    JS 验证
    JS 错误
    JavaScript Break 和 Continue 语句
    JS While
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15179532.html
Copyright © 2011-2022 走看看