【启智树NOIP模拟】生存【父子分治】

题意:有 n n n 个城市连成一棵树,每个城市有 a i a_i ai 个人。接下来 m m m 天每天会发生 k i k_i ki 次灾难,每个灾难会让一个给定城市的人全部死掉。每个人一天可以走一条边,也可以不动。求最多多少人能活过这 m m m 天。

n ≤ 1 0 6 , ∑ k i ≤ 2 × 1 0 6 n\leq 10^6,\sum k_i\leq 2\times 10^6 n106,ki2×106

倒过来考虑,维护在哪些位置的人可以活到最后,相当于要支持以下操作

  1. 把一个点染黑。
  2. 所有白点扩展 1 1 1 步。

对于 2 2 2 操作,一个黑点会变白当且仅当和一个原来的白点相邻。考虑分别维护这个白点是父亲还是儿子。

需要维护的东西:

h u h_u hu 表示真实情况下 u u u 的白儿子个数。

n n n 个 vector 记录每个点 可能 需要被自己更新为白点的所有黑儿子。

封装两个线性结构 q , s q q,sq q,sq ,记录可能会被儿子更新为白点的结点、可能会用来更新黑儿子的结点。

染黑的时候,自己进 q q q,父亲进 s q sq sq,更新父亲的 h h h 和 vector。

然后这一天的行动,把 q q q s q sq sq 一个个取出来判断是否合法并更新自己或 vector 中的儿子,需要染白的记下来稍后处理。

染白的时候,自己进 s q sq sq,父亲进 q q q,更新父亲的 h h h。因为这里更新不了 vector,只能不删,所以不能用 vector 的大小来代替 h h h

复杂度 O ( n + m + ∑ k i ) O(n+m+\sum k_i) O(n+m+ki)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#define MAXN 1000005
using namespace std;
inline int read()
{
	int ans=0;
	char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
typedef long long ll;
vector<int> e[MAXN],lis[MAXN],son[MAXN];
int a[MAXN],col[MAXN],fa[MAXN],h[MAXN];
struct que
{
	int a[MAXN],vis[MAXN],cnt;
	inline void push(int x){if (!vis[x]) vis[a[++cnt]=x]=1;}
	inline int pop(){if (cnt) return vis[a[cnt]]=0,a[cnt--];return 0;}
}q,sq,ans;
void dfs(int u,int f){fa[u]=f;for (int i=0;i<(int)e[u].size();i++) if (e[u][i]!=f) ++h[u],dfs(e[u][i],u);}
inline void die(int u)
{
	if (col[u]) return;
	col[u]=1;
	q.push(u);
	if (fa[u])
	{
		son[fa[u]].push_back(u),--h[fa[u]];
		sq.push(fa[u]);
	}
}
inline void live(int u)
{
	if (!col[u]) return;
	col[u]=0,sq.push(u);
	if (fa[u]) ++h[fa[u]],q.push(fa[u]);
}
int main()
{
	int n,m;
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<n;i++)
	{
		int u,v;
		u=read(),v=read();
		e[u].push_back(v),e[v].push_back(u);
	}
	dfs(1,0);
	for (int i=1;i<=m;i++)
	{
		lis[i].resize(read());
		for (int j=0;j<(int)lis[i].size();j++) lis[i][j]=read();
	}
	for (int T=m;T>=1;T--)
	{
		for (int i=0;i<(int)lis[T].size();i++) die(lis[T][i]);
		for (int u=q.pop();u;u=q.pop()) if (h[u]) ans.push(u);
		for (int u=sq.pop();u;u=sq.pop()) 
			if (!col[u])
			{
				for (int i=0;i<(int)son[u].size();i++)
					ans.push(son[u][i]);
				son[u].clear();				
			}
		for (int u=ans.pop();u;u=ans.pop()) live(u);
	}
	ll ans=0;
	for (int i=1;i<=n;i++) if (!col[i]) ans+=a[i];
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
启智 ROS 用户手册是一本为启智机器人的用户提供的操作指南。该手册的目的是帮助用户了解和掌握如何使用ROS(机器人操作系统)来控制和使用启智机器人。 用户手册以简洁明了的方式介绍了ROS的基本概念和工作原理,以及启智机器人与ROS的衔接方式。手册首先解释了ROS的基本概念,包括节点、话题和服务等,以帮助用户在理解整个ROS系统的基本结构后进行操作。 手册还介绍了如何安装和配置ROS环境,包括安装ROS核心软件和运行必需的依赖。它提供了一步一步的说明,指导用户正确地配置ROS环境,以确保启智机器人与ROS之间的通信正常运行。 用户手册还说明了启智机器人在ROS中的使用方法。它详细介绍了启智机器人的ROS软件包,包括如何启动机器人节点、控制机器人运动和获取传感器数据等。手册通过示例代码和命令解释了每个功能的使用方式,以帮助用户快速上手使用启智机器人。 此外,用户手册还提供了一些常见问题和故障排除的解决办法。用户可以在手册中找到对于常见问题的解答,以便更好地解决遇到的问题。 总而言之,启智 ROS 用户手册是一本全面而详细的操作指南,旨在帮助用户正确地使用ROS控制和操作启智机器人。通过阅读该手册,用户可以了解ROS基本概念、配置ROS环境以及如何使用ROS控制启智机器人,同时也可以学习到如何解决常见问题和故障排除。这本手册对于启智机器人的用户来说是一份宝贵的参考资料,有助于他们更好地利用ROS技术来控制和应用启智机器人。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值