CF899F Letters Removing 题解

CF899F Letters Removing 题解

这好像是个典题。

解法

一个很自然的想法。

考虑开 62 62 62 颗平衡树,即每一种字符都开一颗平衡树,维护的是每种字符出现的位置,每次操作就把对应的平衡树区间删去即可,是很基础的非旋 treap 操作。

实现就是按值分裂。

inline std::pair<fhq_node *,fhq_node *> split(fhq_node *rt,const int k)
{
   
	std::pair<fhq_node *,fhq_node *> ret;
	if(rt==nullptr) return std::make_pair(nullptr,nullptr);
	if(k<rt->val) ret=split(rt->lc,k),rt->lc=ret.second,rt->pushup(),ret.second=rt;
	else ret=split(rt->rc,k),rt->rc=ret.first,rt->pushup(),ret.first=rt;
	return ret;
}

当我搓完平衡树后发现过不了样例,仔细看样例才发现,字符的标号是随着删除操作而变化的。所以我们需要动态的维护每个数的标号,这也是很典的问题。考虑用一个树状数组,初始值都是 1 1 1,表示所有字符都没有被删除,之后每删除一个字符,我们就在树状数组的对应位置减 1 1 1,树状数组中第 k k k 大的数的位置就是删除后的第 k k k 个字符在原序列中的位置。最朴素的想法就是在树状数组上二分。

当然,有比树状数组上二分复杂度更优的做法,就是树状数组上倍增。

注意到树状数组上的节点 c i c_i ci 表示 ∑ j = i − l o w b i t ( i ) + 1 i a j \sum \limits _{j=i-lowbit(i)+1}^i a_j j=ilowbit(i)+1iaj,所以我们从高位向低位枚举答案的每个二进制位即可。

inline int kth(int k)
{
   
	int sum=0,
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值