[BZOJ3600]没有人的算术

题目

传送门 to BZOJ

思路

这个“数”的比较,复杂度是很高的。如果我们可以 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我也只能口胡,我真的打不出来

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值