CF1053E Euler Tour

本文详细解析了 CF1053E 题目,介绍了一个欧拉序合法性的判断条件及解决方案。通过预处理和递归处理,确保了区间内的权值满足特定条件,并使用链表实现,最终达到 O(n) 的时间复杂度。

Address

Solution

  • 可以发现,一个欧拉序 a a a 合法当且仅当:

    1. ∀ 1 ≤ i ≤ 2 n − 1 , 1 ≤ a i ≤ n \forall 1 \le i \le 2n - 1, 1 \le a_i \le n 1i2n1,1ain
    2. a 1 = a 2 n − 1 a_1 = a_{2n - 1} a1=a2n1
    3. ∀ a l = a r \forall a_l = a_r al=ar r − l r - l rl 为偶数且 [ l , r ] [l,r] [l,r] 内出现了恰好 r − l 2 + 1 \dfrac{r - l}{2} + 1 2rl+1 种不同的权值;
    4. 所有满足 a l = a r a_l = a_r al=ar 的区间 [ l , r ] [l,r] [l,r] 只有包含关系。
  • 设当前区间为 [ l , r ] [l,r] [l,r],因为满足 a l ′ = a r ′ a_l' = a_r' al=ar 的区间 [ l ′ , r ′ ] [l',r'] [l,r] 一定代表一棵子树,可以递归处理 ( l ′ , r ′ ) (l',r') (l,r),然后将 [ l ′ , r ′ ] [l',r'] [l,r] 缩成一个点 a l ′ a_{l'} al

  • 对于每个 i i i 预处理下一个和它权值相同的位置,就可以在缩点时顺便判断一下条件 4 4 4

  • 现在 [ l , r ] [l,r] [l,r] 中就不存在权值相同的点,如果区间中出现了少于 r − l 2 + 1 \frac{r - l}{2} + 1 2rl+1 种权值,就将还未出现的权值填在区间的最前面(若权值种类数已经超过 r − l 2 + 1 \frac{r - l}{2} + 1 2rl+1 则无解), 之后从左往右考虑 [ l , r ] [l,r] [l,r] 中每个长度为 3 3 3 的区间,若存在一个长度为 3 3 3 的区间为 xy00yx 的形式,我们就可以将其补成 xyx,然后再缩成一个点 x

  • 将所有能够缩的区间缩完之后可能还会有位置为 0 0 0,我们可以将剩下的位置都填成这棵子树的根。

  • 考虑这样做的正确性:

    1. 若不存在两个不为 0 0 0 的位置相邻,区间的首尾一定已经填入数字且相邻的两个已经填入数字的位置中恰好隔着一个 0 0 0,此时将剩下的位置填成这棵子树的根显然正确;
    2. 若存在两个不为 0 0 0 的位置相邻,缩点之后不为 0 0 0 的位置减少了 1 1 1,为 0 0 0 的位置也减少了 1 1 1,两者的差不变,因此可以看做是递归下去,直到出现第 1 1 1 种情况。
  • 特别地,对于 [ 1 , 2 n − 1 ] [1, 2n - 1] [1,2n1] 我们需要保证首尾相同,进行一些简单的讨论:

    1. a 1 , a 2 n − 1 > 0 a_1, a_{2n - 1} > 0 a1,a2n1>0 a 1 ≠ a 2 n − 1 a_1 \neq a_{2n - 1} a1=a2n1,无解;
    2. a 1 , a 2 n − 1 > 0 a_1, a_{2n - 1} > 0 a1,a2n1>0 a 1 = a 2 n − 1 a_1 = a_{2n - 1} a1=a2n1,递归区间 ( 1 , 2 n − 1 ) (1, 2n - 1) (1,2n1)
    3. a 1 > 0 a_1 > 0 a1>0 a 2 n − 1 > 0 a_{2n - 1} > 0 a2n1>0,将两个数填成相同的,递归区间 ( 1 , 2 n − 1 ) (1, 2n - 1) (1,2n1)
    4. a 1 = a 2 n − 1 = 0 a_1 = a_{2n - 1} = 0 a1=a2n1=0,直接按之前算法处理即可,从左到右合并能保证最后首尾相同且没有剩余位置为 0 0 0
  • 可以用链表实现,时间复杂度 O ( n ) \mathcal O(n) O(n),期望得分 100pts \text{100pts} 100pts

Code

#include <bits/stdc++.h>

template <class T>
inline void read(T &res)
{
	char ch;
	while (ch = getchar(), !isdigit(ch));
	res = ch ^ 48;
	while (ch = getchar(), isdigit(ch))
		res = res * 10 + ch - 48;
}

template <class T>
inline void put(T x)
{
	if (x > 9)
		put(x / 10);
	putchar(x % 10 + 48);
}

const int N = 1e6 + 5;
int a[N], vis[N], nxt[N], pre[N], suf[N];
int n, m, now = 1;

inline void Fail()
{
	puts("no");	
	exit(0);
}

inline int Get()
{
	while (vis[now])
		++now;
	if (now > n)
		Fail();
	vis[now] = 1;
	return now;
}

inline void Delete(int l, int r)
{
	int tl = pre[l], tr = suf[r];
	suf[tl] = tr, pre[tr] = tl;
}

inline void Merge(int l, int r, int &x)
{
	while (x > l && suf[suf[x]] && suf[suf[x]] <= r && !a[x] && a[suf[x]] && a[suf[suf[x]]])
	{
		a[x] = a[suf[suf[x]]];
		Delete(suf[x], suf[suf[x]]);
		x = pre[pre[x]];
	}
	while (x > l && suf[suf[x]] && suf[suf[x]] <= r && a[x] && a[suf[x]] && !a[suf[suf[x]]])
	{
		a[suf[suf[x]]] = a[x];
		Delete(suf[x], suf[suf[x]]);
		x = pre[pre[x]];
	}
}

inline void solve(int l, int r)
{
	if (r - l & 1)
		Fail();
	for (int i = l; i <= r; i = suf[i])
		while (nxt[i])
		{
			if (nxt[i] > r)
				Fail();
			solve(suf[i], pre[nxt[i]]);
			Delete(suf[i], nxt[i]);
			nxt[i] = nxt[nxt[i]];
		}
	int num1 = 0, num2 = 0, rt = a[pre[l]];
	for (int i = l; i <= r; i = suf[i])
		num1 += a[i] > 0, ++num2;
	num2 = (num2 >> 1) + 1;
	if (num1 > num2)
		Fail();
	num2 -= num1; 
	for (int i = l; num2 && i <= r; i = suf[i])
		if (!a[i])
			a[i] = Get(), --num2;	
	for (int i = l; i <= r; i = suf[i])
		Merge(l - 1, r, i);
	for (int i = l; i <= r; i = suf[i])
		if (!a[i])
			a[i] = rt;
	
}

int main()
{
	read(n); 
	if (n == 1)
		return puts("yes\n1"), 0;
	m = (n << 1) - 1;
	for (int i = 1; i <= m; ++i)
		read(a[i]);
	for (int i = 2; i <= m; ++i)
		if (a[i] && a[i - 1] && a[i] == a[i - 1])
			Fail();
	if (a[1] && a[m] && a[1] != a[m])
		Fail();
	a[1] = a[m] = a[1] | a[m];
	for (int i = 0; i <= m + 1; ++i)
		pre[i] = i - 1, suf[i] = i + 1;
	pre[0] = 0;
	for (int i = m; i >= 1; --i)
		if (a[i])
		{
			nxt[i] = vis[a[i]];
			vis[a[i]] = i;
		}
	solve(1, m);
	puts("yes");
	for (int i = 1; i <= m; ++i)
		put(a[i]), putchar(' ');
	return 0;
}

内容概要:本文是一份针对2025年中国企业品牌传播环境撰写的《全网媒体发稿白皮书》,聚焦企业媒体发稿的策略制定、渠道选择与效果评估难题。通过分析当前企业面临的资源分散、内容同质、效果难量化等核心痛点,系统性地介绍了新闻媒体、央媒、地方官媒和自媒体四大渠道的特点与适用场景,并深度融合“传声港”AI驱动的新媒体平台能力,提出“策略+工具+落地”的一体化解决方案。白皮书详细阐述了传声港在资源整合、AI智能匹配、舆情监测、合规审核及全链路效果追踪方面的技术优势,构建了涵盖曝光、互动、转化与品牌影响力的多维评估体系,并通过快消、科技、零售等行业的实战案例验证其有效性。最后,提出了按企业发展阶段和营销节点定制的媒体组合策略,强调本土化传播与政府关系协同的重要性,助力企业实现品牌声量与实际转化的双重增长。; 适合人群:企业市场部负责人、品牌方管理者、公关传播从业者及从事数字营销的相关人员,尤其适用于初创期至成熟期不同发展阶段的企业决策者。; 使用场景及目标:①帮助企业科学制定媒体发稿策略,优化预算分配;②解决渠道对接繁琐、投放不精准、效果不可衡量等问题;③指导企业在重大营销节点(如春节、双11)开展高效传播;④提升品牌权威性、区域渗透力与危机应对能力; 阅读建议:建议结合自身企业所处阶段和发展目标,参考文中提供的“传声港服务组合”与“预算分配建议”进行策略匹配,同时重视AI工具在投放、监测与优化中的实际应用,定期复盘数据以实现持续迭代。
先展示下效果 https://pan.quark.cn/s/987bb7a43dd9 VeighNa - By Traders, For Traders, AI-Powered. Want to read this in english ? Go here VeighNa是一套基于Python的开源量化交易系统开发框架,在开源社区持续不断的贡献下一步步成长为多功能量化交易平台,自发布以来已经积累了众多来自金融机构或相关领域的用户,包括私募基金、证券公司、期货公司等。 在使用VeighNa进行二次开发(策略、模块等)的过程中有任何疑问,请查看VeighNa项目文档,如果无法解决请前往官方社区论坛的【提问求助】板块寻求帮助,也欢迎在【经验分享】板块分享你的使用心得! 想要获取更多关于VeighNa的资讯信息? 请扫描下方二维码添加小助手加入【VeighNa社区交流微信群】: AI-Powered VeighNa发布十周年之际正式推出4.0版本,重磅新增面向AI量化策略的vnpy.alpha模块,为专业量化交易员提供一站式多因子机器学习(ML)策略开发、投研和实盘交易解决方案: :bar_chart: dataset:因子特征工程 * 专为ML算法训练优化设计,支持高效批量特征计算与处理 * 内置丰富的因子特征表达式计算引擎,实现快速一键生成训练数据 * Alpha 158:源于微软Qlib项目的股票市场特征集合,涵盖K线形态、价格趋势、时序波动等多维度量化因子 :bulb: model:预测模型训练 * 提供标准化的ML模型开发模板,大幅简化模型构建与训练流程 * 统一API接口设计,支持无缝切换不同算法进行性能对比测试 * 集成多种主流机器学习算法: * Lass...
Euler tour(欧拉游览)相关主要涉及到Euler Tour Tree(欧拉游览树,简称ETT)。ETT是一种可以维护子树操作的动态树,它的最大优点是能方便地维护子树信息,这是Link-Cut Tree(LCT)做不到的,可用于fully dynamic connectivity(online) [^1]。 ETT支持link(连接)、cut(切断)、单点修改、子树修改以及查询点到根的信息等操作,但貌似不支持换根和链操作 [^2][^3]。其实现方式是维护一棵树的括号序列(也叫欧拉序),具体做法是一个点进栈时记录一次深度优先搜索编号(dfn),出栈时再记录一次dfn,由此得到一个有趣的序列 [^2][^3]。 对于一个欧拉序而言,它合法需要满足一定条件:对于所有 1 ≤ i ≤ 2n - 1,有 1 ≤ ai ≤ n;a1 = a2n - 1;对于所有 al = ar 的情况,r - l 为偶数且 [l, r] 内出现了恰好 (r - l) / 2 + 1 种不同的权值;所有满足 al = ar 的区间 [l, r] 只有包含关系 [^4]。 ### 代码示例 以下是一个简单示意ETT操作的伪代码: ```python # 假设这里定义了ETT的节点类 class ETNode: def __init__(self, value): self.value = value # 其他属性 # 假设ETT类 class EulerTourTree: def __init__(self): self.nodes = [] def link(self, node1, node2): # 实现连接操作 pass def cut(self, node1, node2): # 实现切断操作 pass def single_point_modify(self, node, new_value): # 实现单点修改操作 pass def subtree_modify(self, root_node, modify_function): # 实现子树修改操作 pass def query_to_root(self, node): # 实现查询点到根的信息操作 pass ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值