[BZOJ3600]没有人的算术
发布日期:2021-05-07 01:01:52 浏览次数:16 分类:原创文章

本文共 2203 字,大约阅读时间需要 7 分钟。

题目

思路

这个“数”的比较,复杂度是很高的。如果我们可以 hash \text{hash} hash一下,那么就会变的很简单。

而且,更有意思的是,我们的新“数”是在原有的“数”的基础上产生的,就可以充分利用原有的 hash \text{hash} hash值。

我们用平衡树中的每一个点代表一个当前存在的“数”。即,键值为“数”。当然,满足平衡树的基本性质,中序遍历不降。对于这样一个平衡树,我们很容易的就能写出其 hash \text{hash} hash值。为方便保存,我们用一个有序数对 ( a , b ) (a,b) (a,b)来描述一个“数”( a , b ∈ R a,b\in\R a,bR)。

现在的问题是新的一个“数”。这样的一个“数”,可以利用原有的 hash \text{hash} hash值,将其写为 ( a , b ) (a,b) (a,b) a , b ∈ R a,b\in\R a,bR)。而已经在平衡树中的“数”,我们也用的同样的方法保存,所以可以轻松的 O ( 1 ) \mathcal O(1) O(1)比较。这样一来,我们就 O ( log ⁡ n ) \mathcal O(\log n) O(logn)的找到了应当插入的点。

糟糕的事情到了!新插入的点会导致整个子树的 hash \text{hash} hash值发生变化

但是不怕,我们有 重量平衡树 treap \text{treap} treap 来解决问题。

小知识:重量平衡树。满足每次基本操作影响到的子树大小的 最坏情况 / / /均摊 / / /期望 为 O ( log ⁡ n ) \mathcal O(\log n) O(logn)。其中著名的有替罪羊与 t r e a p treap treap(期望的计算,可以通过枚举到达哪一层来实现,概率为“修正值 f i x fix fix是当前子树的最大值”,即 1 s i z e \frac{1}{size} size1,而影响的大小为 s i z e size size,故期望为树高,即 O ( log ⁡ n ) \mathcal O(\log n) O(logn))。

然后就搞定了!但是 hash \text{hash} hash值的改变,会导致某些点的 ( a , b ) (a,b) (a,b)发生改变—— ( a , b ) (a,b) (a,b)的本质是, f i r s t = first= first=“数” a , s e c o n d = a,second= a,second=“数” b b b的一个“数”。如果 a a a hash \text{hash} hash值改变了,我就得跟着改变。这样一来,复杂度又不正确了。

所以我们不再使用 ( a , b ) ( a , b ∈ R ) (a,b)(a,b\in\R) (a,b)(a,bR),转而使用 ( a , b ) ( a , b ∈ Z ∩ [ 0 , k ] ) (a,b)(a,b\in\Z\cap[0,k]) (a,b)(a,bZ[0,k]),其中 k k k是平衡树的节点数量。也就是说,我们不再使用 hash \text{hash} hash值,而是根据“数”的定义,将一个“数”表示为另外两个“数”。可以让 a = 0 a=0 a=0或者 b = 0 b=0 b=0,表示“数” 0 0 0

然后我们就可以暴力维护了。时间复杂度 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn)

代码

此处仅提供 i n s e r t insert insert的伪代码作为参考。

int id[]; // a_i对应平衡树中的id[i]节点 double f[]; // 每个平衡树节点的hash值 void treap::insert(pair p){   	当前处理到了节点o	if(o == 0){   		o = newNode(p.first,p.second);		return ; // 建新点,数据为p 	}	if(make_pair(f[data[o][0]],f[data[o][1]]) < make_pair(f[p.first],f[p.second])		insert(右子树); // 数据都存储的是两个节点编号 	else insert(左子树);}void insert(int l,int r,int k){   	treap.insert(make_pair(id[l],id[r]));	将f进行调整 /* 可以使用类似线段树的方法,给每个节点一个开区间值域(L,R),然后 	该点的hash值取mid=(L+R)/2,然后左右子树递归为(L,mid)与(mid,R) */	id[k] = cntNode; // cntNode是新申请的节点(即刚刚插入的节点) }

然后对于平衡树,可以维护一个最大的 h a s h hash hash值(和其对应的 a a a的下标)。

a a a的下标,可以通过每一个点都存储一下做到。也就是说,

data[o][2] = index; // index是参数,对应的下标 

MD我也只能口胡,我真的打不出来

上一篇:React+Ant design日期组件DatePicker设置结束时间不能小于开始时间
下一篇:css 强制不换行超出显示省略号,自动换行超出显示省略号

发表评论

最新留言

表示我来过!
[***.240.166.169]2025年03月24日 05时58分12秒