4.9 省选模拟赛 圆圈游戏 树形dp set优化建图

由于圆不存在相交的关系 所以包容关系形成了树的形态 其实是一个森林 不过加一个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;
}

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

原文地址:https://www.cnblogs.com/chdy/p/12681119.html

时间: 2024-11-05 14:57:54

4.9 省选模拟赛 圆圈游戏 树形dp set优化建图的相关文章

4.3 省选模拟赛 石子游戏 树上博弈

注意观察题目 每个点都只能将石子给自己的两个儿子 且石子个数>=1. 显然 这是一个阶梯NIM. 只有和最后一层的奇偶性相同的层才会有贡献 证明也很显然. 那么这其实就是近乎NIM游戏了 胜负自然取决于所有有贡献的石子堆的异或和. 但是 上午我傻了的一点 没有分清SG函数和NIM游戏的联系. 在NIM游戏中SG函数其实就是每个有贡献的石子堆的石子数. 再来看这道题 由于异或和一定 暴力枚举移动哪一堆石子 判断是否可行即可. 这个操作其实是 NIM游戏的证明问题了.解决的方案是 观察一下移动后造成

4.15 省选模拟赛 编码 trie树 前缀和优化建图 2-sat

好题 np. 对于20分 显然可以爆搜. 对于50分 可以发现每个字符串上的问号要么是0,要么是1.考虑枚举一个字符串当前是0还是1 这会和其他字符串产生矛盾. 所以容易 发现这是一个2-sat问题. 拆点 把任意两个产生矛盾的字符串进行连边.然后最后判矛盾即可. n^2枚举 建图 判断矛盾时使用字符串hash 要分类讨论4种情况. using namespace std; const int MAXN=1010,maxn=500010,cc1=19260817,cc2=114514; int

P2016 战略游戏——树形DP大水题

P2016 战略游戏 树形DP 入门题吧(现在怎么是蓝色标签搞不懂): 注意是看见每一条边而不是每一个点(因为这里错了好几次): #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=3010; int pre[maxn],last[maxn],other[maxn],l; void add(int x,int y) { l++; pre[l]

@省选模拟赛03/16 - T3@ 超级树

目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取一棵深度为 k 的满二叉树,对每个节点向它的所有祖先连边(如果这条边不存在的话). 例如,下面是一个 4-超级树: 请统计一棵 k-超级树 中有多少条不同的简单有向路径,对 mod 取模. input 一行两整数 k, mod. output 一行一整数表示答案. example input1: 2

2018.3.10 省选模拟赛

从这里开始 概况 Problem A 三元组 Problem B 攻略 Problem C 迂回 概况 这是省选T1合集?还是欢乐AK赛? 全班一半以上的人三道题都会做qwq. Doggu还剩一小时时以为自己AK了,然后玩了一小时.虽然最终被卡了20分的常数. ZJC 1个半小时AK?Excuse me? 我这条大咸鱼到最后10分钟才敲完了T1,然后发现线段树要T掉. 发自内心鄙视垃圾出题人卡常数,本来的欢乐AK变成280. 教练给我们考4个小时的试,题面上也这么写的,看题解,woc,考试时间3

2018.2.12 省选模拟赛

题目大意 (题目很简洁了,不需要大意) 其实显而易见地可以发现,当被卡一次后后面的路程都是固定了的. 可以用类似动态规划的思想来进行预处理.现在的问题就是怎么知道在某个位置刚等完红灯然后出发会在哪个路口再次被卡. 尝试画一画图: 其中横轴表示位置,纵轴表示时间,长方体表示红灯时段.有用的部分长度只有$r + g$,所以在模意义下弄一下就可以减少很多重复和无用状态: 但是这样仍然不好处理上面提到的问题,考虑让线段横着走,第一个撞着的长方形就是答案.为了实现这个目标,就每个长方形向下移动一段(移动的

2018/3/9 省选模拟赛 0分

第二题模拟扫一遍就可以过,不能更划算了.q=1的30分写的比100分还麻烦,有趣哦. 破暴力40分也没什么可写了,日常辣鸡吃枣药丸. 原文地址:https://www.cnblogs.com/137shoebills/p/8533870.html

2018/3/29 省选模拟赛 80

我真是太菜了... T1 10分纯暴力没写,20分容斥也没写(人就是懒死的).还有30分矩乘不会 正解 <IOI2018 中国国家集训队第一阶段作业题解部分 - 杭州第二中学 吴瑾昭.pdf>最后一题 T2  以为自己能拿到50分,但是其实那个暴力算法只能过10分的点,n=2000的20分数据用n^3带剪枝过不了,所以拿了30分. 正解 <计数与期望问题选讲 CLJ.pdf>最后一题 我记得我以前好像看到过这个文档但是没读过..今天读一下 T3 依然是分情况50分,30分树归20分

2018.2.23 省选模拟赛

从这里开始 Problem A cycle Problem B meal Problem C naive Problem A cycle 判断是否有经过一个点的负环,我们可以跑最短路.判断这个点到自己的最短路是否是负数. 于是可以二分环大小跑dfs版spfa. 于是可以分层图做时间复杂度四方的dp. (YYR给的数据水得吓人,这两个做法居然都跑过了.然后都被我和jmr卡掉了) 注意到如果一个点走不超过$k$条边回到自己的最短路的长度是负数,那么走不超过$k + 1$条边也是. 因此我们可以二分答