AtCoder Regular Contest 148

C Lights Out on Tree

挺好的一道题,简单写一下题解吧。
首先有挺多很 naive 的结论:

  • 每个节点按两遍等于没按。
  • 熄灭所有的灯只有一种方案。

其实将灯熄灭的方案无非就是从上往下 dfs,如果当前灯是量的,就在当前节点按一下,否则不按。这样我们就可以写出暴力了。

考虑一下,如果树上只有一个节点 u 开始亮灯,那么需要按的灯即为 uu 的所有儿子,设这个集合为 {v}

进一步考虑一下,若初始的亮灯集合为 {u1,u2,um},那么所有需要按的集合即为 {v1,v2,vm},再根据上面的第一个结论:每个节点按两遍等于没按,所以只需要求出在 {v1,v2,vm} 集合中出现次数为奇数的节点个数。

可以用线段树维护,但是进一步观察发现:每个节点如果出现两遍当且仅当它的父亲也在集合 {u1,u2,um} 中,这样我们就可以在 O(n) 的时间内解决本题了。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,q,son[N],p[N],m,v[N],mp[N];
signed main()
{
	cin>>n>>q;
	for(int i=1;i<=n;++i)son[i]++;
	for(int i=2;i<=n;++i){cin>>p[i];son[p[i]]++;}
	while(q--)
	{
		int ans=0;cin>>m;
		for(int i=1;i<=m;++i)
		{
			cin>>v[i];mp[v[i]]=1;ans+=son[v[i]];
			if(mp[p[v[i]]])ans-=2;//如果当前节点的父亲在集合中,答案减2 
		} 
		for(int i=1;i<=m;++i)mp[v[i]]=0;
		cout<<ans<<endl;
	}
	return 0;
}
posted @   lnwhl  阅读(84)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示