[分块][STL][树]【Centroids】不一样的解法

news2024/9/22 13:41:39

前言

一道好题,也就花了我一个下午而已。

本人做法比较清奇,可以当做开阔思路参考,并不太建议实操(太难调了!)。

文章较啰嗦,谅解。

思路

众所周知,我并不太喜推式子,所以我们考虑直接根据题目限定的条件硬刚。

首先,我们先假定 1 1 1 为根,并求出每个点的子树的大小,记为数组 s i z e size size,并且再维护一下每一个点的时间戳。

接着我们考虑一种特殊情况,即如果 1 1 1 可以为树的重心的情况,那么他就会有接下来的两种子情况:

  • 他所有的儿子的 s i z e size size 全部小于等于 n 2 \dfrac {n}{2} 2n

  • 有一个儿子 x x x s i z e size size 大于 n 2 \dfrac {n}{2} 2n,且这个儿子的子树上一定能找到一个点 y y y 满足 s i z e x − s i z e y ≤ n 2 , s i z e y ≤ n 2 size_x-size_y \le \dfrac{n}{2},size_y\le \dfrac{n}{2} sizexsizey2n,sizey2n。(把这个子树拆下来接到 1 1 1 上就可以满足重心的条件)

第二种情况不是很理解的话可以看下面这张图:

只有两种情况满足其一,那么 1 1 1 就可以成为树的重心。

接下来,我们迁移到一般的情况,那么就需要考虑除了他子树以外的情况。

对于树上的任意节点 x x x,要让他成为树的重心,就会有接下来的三种情况。

  • 他所有的儿子的 s i z e size size 全部小于等于 n 2 \dfrac{n}{2} 2n,并且 n − s i z e x ≤ n 2 n-size_x \le \dfrac{n}{2} nsizex2n

  • 同根节点的第二种情况。

  • n − s i z e x > n 2 n-size_x > \dfrac{n}{2} nsizex>2n,即删除 x x x 后,不属于他子树的那一部分超过了重心的限制。那么在其中,我们又要分为两种情况。首先选择一个不在 x x x 子树上的点 y y y。如果 y y y 不在根节点到 x x x 的那条链上,那么只需要满足 s i z e y ≤ n 2 , n − s i z e x − s i z e y ≤ n 2 size_y \le \dfrac{n}{2},n-size_x-size_y\le \dfrac{n}{2} sizey2n,nsizexsizey2n。否则,我们拆下来的,就是除了 y y y 子树以外的部分,接到 x x x 上面去(毕竟你不可以把 x x x 的子树也拆下来,不然就会没有任何效果。),即满足条件 s i z e y − s i z e z ≤ n 2 , n − s i z e y ≤ n 2 size_y-size_z\le \dfrac{n}{2},n-size_y \le \dfrac{n}{2} sizeysizez2n,nsizey2n,只要找到一个符合条件的 y y y 即可。

那么接下来,问题就转化为了 x x x 能不能找到一个符合条件的 y y y。(毕竟第一个条件很好解决。)

接着继续转化问题,对于情况2,我们可以移一下项,将其转化为 y y y 满足条件 s i z e x − n 2 ≤ s i z e y ≤ n 2 size_x-\dfrac{n}{2} \le size_y \le \dfrac{n}{2} sizex2nsizey2n,且 d f n x ≤ d f n y ≤ d f n x + s i z e x − 1 dfn_x \le dfn_y \le dfn_x+size_x-1 dfnxdfnydfnx+sizex1

对于情况三的第一种情况,我们也可以移一下项,转化为 n − s i z e x − n 2 ≤ s i z e y ≤ n 2 n-size_x-\dfrac{n}{2} \le size_y \le \dfrac{n}{2} nsizex2nsizey2n,且 d f n y < d f n x , d f n y > d f n x + s i z e x − 1 dfn_y<dfn_x,dfn_y>dfn_x+size_x-1 dfny<dfnx,dfny>dfnx+sizex1(对于不在链上这一限制,后面会说怎么处理)。

这两种情况都可以看做有四个常数 p , q , l , r p,q,l,r p,q,l,r,判断是否有对于 x ∈ [ p , q ] , y ∈ [ l , r ] x \in [p,q],y \in [l,r] x[p,q],y[l,r] 存在 x = s i z e y x=size_y x=sizey

显然,我们可以对于 s i z e size size 分块,然后开两个 s e t set set a , b a,b a,b a x a_x ax (为什么用set后面会解释。)里面放所有 s i z e = x size=x size=x 的所有下标, b x b_x bx s i z e size size 属于 x x x 这个块的所有的下标。最后查询时,以 s i z e size size 为第一维,对于散块,在 a a a 中二分,看有没有满足属于 [ l , r ] [l,r] [l,r] 的值,对于整块,则在 b b b 中二分。

接着,我们看向比较难处理的情况三的第二种情况。

我们可以动态维护一个数组,依次储存从根到该节点的链上的所有 s i z e size size 值,可以发现是单调递减。并且记得在加入数组时,删除他在 a , b a,b a,b 中的值,在删除数组元素时,加回去。(因为必须要保证在情况三的情况1解决时要不包含这些在链上的元素)。这里的删除和加入就解释了为什么要采用 set。接着可以先在数组中二分找出满足 n − s i z e y ≤ n 2 n-size_y \le \dfrac{n}{2} nsizey2n y y y 的范围,然后在这个范围中继续二分找出是否存在满足 s i z e y − s i z e z ≤ n 2 size_y-size_z\le \dfrac{n}{2} sizeysizez2n y y y,那么就解决了情况3的第二种情况。

时间复杂度,分块+二分,及 n n log ⁡ n n \sqrt n \log n nn logn,但因为二分的区间长度不可能每次都是顶着的,所以远远达不到这个上界,但仍然很慢。

所以问题就 迎刃而解 了!

代码

#include<bits/stdc++.h>
using namespace std;
int n;
struct node
{
	int tar,nxt;
}arr[800005];
int fst[400005],cnt;
void adds(int x,int y)
{
	arr[++cnt].tar=y,arr[cnt].nxt=fst[x],fst[x]=cnt;
}
int size[400005],dfn[400005],tot,rnk[400005];
int klen,len;
set<int> a[400005],b[100005];
bool dp[400005];
void dfs(int x,int last)
{
	dfn[x]=++tot;
	rnk[dfn[x]]=x;
	for(int i=fst[x];i;i=arr[i].nxt)
	{
		int j=arr[i].tar;
		if(j==last) continue;
		dfs(j,x);
		size[dfn[x]]+=size[dfn[j]];
	} 
	size[dfn[x]]++;
}
int getk(int x)
{
	return ceil(x/(klen*1.0));
}
int lk(int x)
{
//	cout<<x<<" "<<(x-1)*klen+1<<endl;
	return (x-1)*klen+1;
}
int rk(int x)
{
	if(x==len) return n;
	else return x*klen;
}
bool ch1(int p,int x,int y)
{
//	cout<<p<<" "<<x<<" "<<y<<endl;
	set<int>::iterator q=a[p].lower_bound(x);
	if(q==a[p].end()) return false;
	else if(*q<=y) return true;
	else return false;
}
bool ch2(int p,int x,int y)
{
	set<int>::iterator q=b[p].lower_bound(x);
	if(q==b[p].end()) return false;
	else if(*q<=y) return true;
	else return false;
}
bool check(int l,int r,int x,int y)
{
//	cout<<l<<" "<<r<<" "<<x<<" "<<y<<endl;
	if(l>r) return false;
	int p=getk(x)+1,q=getk(y)-1;
	int pp=rk(getk(x)),qq=lk(getk(y));
	if(p>q)
	{
		for(int i=x;i<=y;++i) if(ch1(i,l,r)) return true;
	}
	else
	{
		for(int i=x;i<=pp;++i) if(ch1(i,l,r)) return true;
		for(int i=qq;i<=y;++i) if(ch1(i,l,r)) return true;
		for(int i=p;i<=q;++i) if(ch2(i,l,r)) return true;
	}
	return false;
}
int p[400005],tail=400001;
void add(int x)
{
	p[--tail]=size[dfn[x]];
	x=dfn[x];
	set<int>::iterator q=a[size[x]].lower_bound(x);
	a[size[x]].erase(q);
	q=b[getk(size[x])].lower_bound(x);
	b[getk(size[x])].erase(q);
}
void del(int x)
{
	tail++;
	x=dfn[x];
	a[size[x]].insert(x);
	b[getk(size[x])].insert(x);
}
void get_ans(int x,int last)
{
	if(x!=1)
	add(x);
	int flg=0,num=0,l,r;
	bool bj=0;
	for(int i=fst[x];i;i=arr[i].nxt)
	{
		int j=arr[i].tar;
		if(j==last) continue;
		if(size[dfn[j]]>n/2) flg++,num=size[dfn[j]],l=dfn[j],r=dfn[j]+size[dfn[j]]-1;
		get_ans(j,x);
	}
	del(x);
	if(n-size[dfn[x]]>n/2) flg++,num=n-size[dfn[x]],bj=1;
	if(flg>=2) return;
	if(flg==0)
	{
		dp[x]=1;
		return;
	}
	if(!bj)
	{
		if(check(l,r,num-n/2,n/2))
		dp[x]=1;
	}
	else
	{	
		//x,x+size[x]-1
		if(check(1,dfn[x]-1,num-n/2,n/2)||check(dfn[x]+size[dfn[x]],n,num-n/2,n/2))
		dp[x]=1;
		if(dp[x])
		{
			return;
		}
//		cout<<x<<" "<<1<<endl;
		int ll=lower_bound(p+tail,p+400000+1,n-n/2)-p,rr=400000,mid,ans;
		while(ll<=rr)
		{
			mid=(ll+rr)>>1;
			if(p[mid]-size[dfn[x]]<=n/2)
			{
				dp[x]=1;
				break;
			}
			else
			{
				rr=mid-1;
			}
		}
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;++i)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		adds(x,y);
		adds(y,x);
	}
	klen=sqrt(n),len;
	if(klen*klen==n) len=klen;
	else len=klen+1;
	dfs(1,0);
	for(int i=1;i<=n;++i) a[size[i]].insert(i),b[getk(size[i])].insert(i);
	get_ans(1,0);
	for(int i=1;i<=n;++i) printf("%d ",dp[i]);
}
暴力出奇迹!!!!!

T h e   E n d \Huge\mathscr{The\ End} The End

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732912.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

37.RocketMQ之Broker消息存储源码分析

highlight: arduino-light 消息存储文件 rocketMQ的消息持久化在我们在搭建集群时都特意指定的文件存储路径,进入指定的store目录下就可以看到。 下面介绍各文件含义 CommitLog 存储消息的元数据。produce发出的所有消息都会顺序存入到CommitLog文件当中。 CommitLog由多个文件…

javassist implements interface 模拟mybatis 生成代理类

动态创建代理对象的工具类 package com.wsd.util;import org.apache.ibatis.javassist.ClassPool; import org.apache.ibatis.javassist.CtClass; import org.apache.ibatis.javassist.CtMethod; import org.apache.ibatis.session.SqlSession;import java.lang.reflect.Const…

[工业互联-14]:机器人操作系统ROS与ROS2是如何提升实时性的?

目录 第1章 简介 第2章 历史 第3章 特点 &#xff08;1&#xff09;点对点设计 &#xff08;2&#xff09;不依赖编程语言 &#xff08;3&#xff09;精简与集成 &#xff08;4&#xff09;便于测试 &#xff08;5&#xff09;开源 &#xff08;6&#xff09;强大的库及…

ESP32连接云服务器【WebSocket】

ESP32连接云服务器【ESP32宝塔面板】 文章目录 ESP32连接云服务器【ESP32宝塔面板】&#x1f468;‍&#x1f3eb;内容1&#xff1a;背景&#x1f468;‍⚖️内容2&#xff1a;服务器配置&#x1f468;‍&#x1f4bb;内容3&#xff1a;ESP32配置 &#x1f468;‍&#x1f3eb;…

3.5.核函数的定义和使用

目录 前言1. 核函数2. 核函数案例总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习精简 CUDA 教程-核函数 课程大纲可看下面…

使用infura创建以太坊网络

创建账号 https://www.infura.io/zh 进入控制台Dashboard&#xff0c;选择CREATE API KEY 创建成功后&#xff0c;进入API KEY查看&#xff0c;使用PostMan测试 返回result即为当前区块。

Linux安装配置Oracle+plsql安装配置(超详细)

注意&#xff1a;本文有大量的界面截图&#xff0c;如观看效果不佳可前往文字版&#xff1a; 目录 1 安装虚拟机系统 1.1 安装虚拟机 2.配置虚拟机 2.1 设置机器名 2.2 修改域名映射 2.3 固定IP地址 ​ 2.4 关闭防火墙 2.5 更改安全机制 2.6 重启reboot 3 修改配置 3.1 …

2.深度学习:用Python实现深度神经网络(简单易懂)

深度学习是人工智能领域中的一个热门话题&#xff0c;也是目前业界最具前景和发展潜力的领域之一。本文将会介绍如何用Python实现深度神经网络&#xff0c;编写自己的深度学习模型。作为一篇简单易懂的教程&#xff0c;本文将会从以下两个方面进行讲解&#xff1a;1. 基础知识介…

java环境搭建2-idea安装激活

windows环境装Java开发环境与idea安装激活 安装jdk安装idea激活idea新建项目开启Java学习 java环境搭建2-idea安装激活 之前安装了wslLinux子环境的Java开发环境,但是再许多地方没有人使用vscode进行Java开发,因为环境配置很麻烦,还有各种插件. windows环境装Java开发环境与ide…

尚无忧多城市共享自助台球室台球厅预约开灯开门小程序源码

1、定位功能&#xff1a;可定位附近是否有店 2、能通过关键字搜索现有的店铺 3、个性轮播图展示&#xff0c;系统公告消息提醒 4、个性化功能展示&#xff0c;智能排序&#xff0c;距离、价格排序 5、现有店铺清单展示&#xff0c;订房可查看房间单价&#xff0c;根据日期、…

在 FPGA 上通过 2D CNN 进行高效视频理解的 TSM 网络

在这个项目中&#xff0c;将在线和离线 TSM 网络部署到 FPGA&#xff0c;通过 2D CNN 执行视频理解任务。 介绍 在这个项目中&#xff0c;展示了 Temporal-Shift-Module ( https://hanlab.mit.edu/projects/tsm/)在 FPGA 上解决视频理解问题的实用性和性能。 TSM 是一种网络结构…

C++常用库函数 2.字符分类函数

函数名&#xff1a;isalnum 函数原型&#xff1a;int isalnum(int c)&#xff1b; 所需头文件&#xff1a;<cctype> 功能&#xff1a;测试 c 是否字母或数字。 返回值&#xff1a;如果 c 在 A&#xff5e;Z、a&#xff5e;z 或0&#xff5e;9的范围内&#xff0c;则返回…

002-集成Dubbo

目录 集成架构架构分析 Spring boot 集成引入依赖提供API 调用桥梁添加Dubbo服务服务提供者-服务实现服务提供者-添加配置服务消费者-添加配置服务消费者-配置消费端请求任务服务调用 扩展为什么要新增Dubbo协议 集成 架构 架构分析 Dubbo作为一个RPC调用框架作用就是让服务具…

使用Yfinance和Plotly分析金融数据

大家好&#xff0c;今天我们用Python分析金融数据&#xff0c;使用Yfinance和Plotly绘制图表&#xff0c;带你了解在Python中使用Plotly制作图表&#xff0c;利用Plotly强大的图表功能来分析和可视化金融数据。 导语 在本文中&#xff0c;我们将深入研究Plotly&#xff0c;从…

Linux安装配置Oracle+plsql安装配置(详细)

如果觉得本文不够详细&#xff0c;没有效果图&#xff0c;可移步详细版&#xff1a; Linux安装配置Oracleplsql安装配置&#xff08;超详细&#xff09;_超爱慢的博客-CSDN博客 目录 1.安装虚拟机系统 1.安装虚拟机 2.配置虚拟机 1.设置机器名 2.修改域名映射 3.固定IP…

I.MX RT1170之FlexSPI(4):HyperRAM手册分析和参数配置详解

在上一篇文章中我分析了NOR Flash的手册和FlexSPI的相关配置&#xff0c;在这篇文章中&#xff0c;我将以HyperRAM为例&#xff0c;看看八线的HyperRAM在硬件设计和软件配置上有增加什么引脚和参数&#xff0c;然后以ISIS型号为IS66WVH64M8DALL/BLL的HyperRAM为例&#xff0c;看…

402 · 连续子数组求和

链接&#xff1a;LintCode 炼码 - ChatGPT&#xff01;更高效的学习体验&#xff01; 题解&#xff1a; 九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧 九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业…

微信小程序开发与应用——字体样式设置

要求&#xff1a;设置字体样式。 1、打开微信开发者工具&#xff0c;创建一个小程序&#xff0c;如下&#xff1a; 2、设置小程序的项目名称和路径&#xff0c;并选择开发语言为JavaScript&#xff0c;如下&#xff1a; 3、小程序的主体部分由三个文件组成&#xff0c;且都要…

2023.07.08力扣6题

167. 两数之和 II - 输入有序数组 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 < …

Carla与Ros联合仿真教学与踩坑经历

Carla与Ros联合仿真教学与踩坑经历 前言 本人需要用到carla进行仿真&#xff0c;做实验&#xff0c;研究了这个平台几个月。 需要注意的是&#xff0c;本人没有保留所有的ros包&#xff0c;而是选择一些进行使用&#xff0c;其他大家可以进行扩展。 carla0.9.5版本和carla0.…