zoukankan      html  css  js  c++  java
  • 4.9 省选模拟赛 圆圈游戏 树形dp set优化建图

    avatar
    avatar

    由于圆不存在相交的关系 所以包容关系形成了树的形态 其实是一个森林 不过加一个0点 就变成了树。

    考虑对于每个圆都求出最近的包容它的点 即他的父亲。然后树形dp即可。暴力建图n^2.

    const int MAXN=100010;
    int n,m,len;
    struct wy
    {
    	ll x,y,r,w;
    	inline int friend operator <(wy a,wy b){return a.r<b.r;}
    }t[MAXN];
    int f[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1];
    inline db dist(int x,int y){return sqrt((pf(t[x].x-t[y].x)+pf(t[x].y-t[y].y))*1.0);}
    inline void dp(int x)
    {
    	f[x]=t[x].w;
    	int sum=0;
    	go(x)
    	{
    		dp(tn);
    		sum+=f[tn];
    	}
    	f[x]=max(f[x],sum);
    }
    inline void add(int x,int y)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    }
    int main()
    {
    	freopen("circle.in","r",stdin);
    	freopen("circle.out","w",stdout);
    	get(n);
    	rep(1,n,i)
    	{
    		ll x,y,r,w;
    		get(x);get(y);
    		get(r);get(w);
    		t[i]=(wy){x,y,r,w};
    	}
    	sort(t+1,t+1+n);
    	rep(1,n,i)//对于每个i找到一个最小的j.
    	{
    		db minn=INF;int p=0;
    		rep(i+1,n,j)
    		{
    			db d=dist(i,j);
    			if(t[j].r-t[i].r-d<0)continue;
    			if(t[j].r-t[i].r-d<minn)
    			{
    				minn=t[j].r-t[i].r-d;
    				p=j;
    			}
    		}
    		add(p,i);
    	}
    	dp(0);put(f[0]);return 0;
    }
    

    考虑优化建图 一个思路 把所有的边都连上 然后topsort建图 但是这并不能线段树优化建图什么的。

    或者直接对于每个圆找到离自己最近的圆然后判断关系连边。

    对于后者 可以考虑以扫描线的方式建图 对于每个圆我们都在左边插入 右边删除。

    在插入的时候寻找父亲 可以发现此时圆对于离自己最近的圆要么是包含的 要么是兄弟。

    对于前者直接找到了父亲 对于后者 兄弟的父亲就是自己的父亲。

    考虑找到最近的圆可以使用圆的上半部分来判断 对于上半部分找到自己左端点离自己最近的圆弧 如果是下半圆弧就是兄弟 上半圆弧那么必然是父亲。

    用set维护距离 可以发现这些圆弧的相对位置不变 所以总复杂度nlogn.

    const ll MAXN=200010,maxn=3000010;
    ll n,T,cnt,len;
    ll f[MAXN];
    ll lin[MAXN],ver[MAXN<<1],nex[MAXN<<1];
    struct wy{ll x,y,z,r,id;}t[MAXN];
    struct jl{ll x,y,op;}q[MAXN];
    inline ll cmp(jl a,jl b){return a.x<b.x;}
    inline void dp(ll x)
    {
    	f[x]=t[x].z;
    	ll sum=0;
    	go(x)
    	{
    		dp(tn);
    		sum+=f[tn];
    	}
    	f[x]=max(f[x],sum);
    }
    inline void add(ll x,ll y)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    }
    struct data
    {
    	ll id,op;
    	//data(){};
    	inline double calc()const
    	{
    		if(op)return t[id].y+sqrt((pf(t[id].r)-pf(t[id].x-T))*1.0);
    		return t[id].y-sqrt((pf(t[id].r)-pf(t[id].x-T))*1.0);
    	}
    	inline ll friend operator <(data a,data b)
    	{
    		double x=a.calc();db y=b.calc();
    		if(fabs(y-x)>EPS)return x<y;
    		if(a.op!=b.op)return a.op<b.op;
    		return a.id<b.id;
    	}
    };
    set<data>s;
    set<data>::iterator it;
    signed main()
    {
    	freopen("circle.in","r",stdin);
    	freopen("circle.out","w",stdout);
    	get(n);
    	rep(1,n,i)
    	{
    		ll x,y,z,r;
    		get(x);get(y);get(r);get(z);
    		t[i]=(wy){x,y,z,r};
    		q[++cnt]=(jl){t[i].x-t[i].r,i,1};
    		q[++cnt]=(jl){t[i].x+t[i].r,i,-1};
    	}
    	sort(q+1,q+1+cnt,cmp);
    	//rep(1,cnt,i)cout<<q[i].y<<endl;
    	rep(1,cnt,i)
    	{
    		T=q[i].x;
    		//cout<<(*s.begin()).id<<' '<<(*s.begin()).op<<endl;
    		if(q[i].op==1)
    		{
    			s.insert((data){q[i].y,1});
    			it=s.find((data){q[i].y,1});
    			++it;
    			if(it==s.end())f[q[i].y]=0;
    			else
    			{
    				if((*it).op==0)f[q[i].y]=f[(*it).id];
    				else f[q[i].y]=(*it).id;
    			}
    			s.insert((data){q[i].y,0});
    		}
    		else
    		{
    			s.erase((data){q[i].y,1});
    			s.erase((data){q[i].y,0});
    		}
    	}
    	rep(1,n,i)add(f[i],i);
    	dp(0);put(f[0]);return 0;
    }
    

    一些细节:两个圆并列的时候注意让下半圆弧优先 注意距离的计算公式。

  • 相关阅读:
    Appium [安装包] Appium 国内下载地址 (百度云盘,已更新至 AppiumDesktop_1.7.1)(转载)
    PLSQL 触发器
    Java解析Json数据的两种方式
    easyui combobox 动态加载数组数据
    js控制easyui datagrid列的显示和隐藏
    Js中for循环的阻塞机制
    数据库中的视图
    严重:Error configuring application listener of class org.springframework.web.util.IntrospectorCleanupListener
    eclipse背景设置什么颜色缓解眼睛疲劳之一
    Maven详解
  • 原文地址:https://www.cnblogs.com/chdy/p/12681119.html
Copyright © 2011-2022 走看看