codeforces EDU segment tree

本文以codeforces EDU segment tree为资料

introdcution

线段树是一种采用了分治和记忆化的数据结构,主要用于区间查询和修改。

  对 [ l , r ) [l,r) [l,r)的区间,它的结果由 [ l , m i d ) , [ m i d , r ) [l,mid),[mid,r) [l,mid),[mid,r)决定,比如 m i n ( [ l , r ) ) = m i n (   m i n ( [ l , m i d ) ) ,   m i n ( [ m i d , r ) )   ) min([l,r))=min(\ min([l,mid)),\ min([mid,r))\ ) min([l,r))=min( min([l,mid)), min([mid,r)) ),那么我们可以建立一个以最长区间的合适长度(一般为二的幂次)为叶子节点的数量,从根节点自上而下建树,叶子节点的值由外部输入初始化,非叶子节点的值由子节点建立。对于节点 x x x,有 l x , r x , v a l u e s lx,rx,values lx,rx,values,其中 l x , r x lx,rx lx,rx表示节点 x x x的范围, v a l u e s values values是值。 m i d = ( l x + r x ) / 2 mid=(lx+rx)/2 mid=(lx+rx)/2,那么由节点 x x x向下搜索 2 x + 1 2x+1 2x+1节点 ( l x , m i d , v a l u e s ) (lx,mid,values) (lx,mid,values) 2 x + 2 2x+2 2x+2节点 ( m i d , r x , v a l u e s ) (mid,rx,values) (mid,rx,values),搜索完后更新 x x x节点。根节点的范围为 [ 0 , s i z e ) [0,size) [0,size) s i z e size size表示最小 ⩾ n \geqslant n n的二次幂 2 k 2^k 2k,这样我们就完成了建树,建树的范围最大为 2 n 2n 2n,总节点数最大为 4 n 4n 4n
  对于查询过程 l , r l,r l,r,我们仍从根节点向下搜索涉及到的范围。对于 l x ⩾ r   o r   r x ⩽ l lx \geqslant r\ or\ rx \leqslant l lxr or rxl,那么该节点 x x x的范围不在查询范围内;可以直接退出,对于 l x ⩾ l   a n d   r x ⩽ r lx \geqslant l\ and\ rx \leqslant r lxl and rxr,那么该节点 x x x的范围完全在查询范围内,也可以直接退出;剩下的情况是两者有交叉部分:那么我们仍然考虑分治的思想,向下搜索 2 x + 1 , 2 x + 2 2x+1,2x+2 2x+1,2x+2节点,查询范围可以不变的向下传递。采用递归的方式可以很好的在叶子节点更新后返回非叶子节点更新。

problems & solutions

step 4

A. Sign alternation

建树,更新,查询时考虑正负即可

B. Cryptography

矩阵乘法,对calc部分进行修改即可
但这题由于输入输出的关系容易超时,fast I/O改进
同时,考虑sparse table,减少建树所需要的点的数量

C. Number of Inversions on Segment

i n v [ l , r ) = i n v [ l , m i d ) + i n v [ m i d , r ) + n u m ( a i > a j )   ( i ∈ [ l , m i d ) , j ∈ [ m i d , r )   ) inv[l,r)=inv[l,mid)+inv[mid,r)+num(a_i>a_j)\ (i\in [l,mid),j\in [mid,r)\ ) inv[l,r)=inv[l,mid)+inv[mid,r)+num(ai>aj) (i[l,mid),j[mid,r) )
n u m ( a i > a j ) num(a_i>a_j) num(ai>aj)可以用颜色桶排解决
由于颜色种类只有40,那么时间复杂度是可以接受的

D. Number of Different on Segment

同样考虑单个颜色,在区间 [ l , r ) [l,r) [l,r)范围是否出现只需要考虑 s u m [ l , r ) sum[l,r) sum[l,r)

E. Earthquakes

对节点的更新仅是单点的,考虑到每次查询区间 ] l , r ) ]l,r) ]l,r) x x x小的值时都会将其节点更新为 i n f inf inf,那么以最小值的方法建立线段树,每次查询的均摊复杂度是 n l o g ( N ) + O ( n u m ) n + 1 , ∑ n u m ⩽ N , O ( n u m ) = l o g ( n ) \frac {nlog(N)+O(num)}{n+1},\sum num\leqslant N,O(num)=log(n) n+1nlog(N)+O(num),numN,O(num)=log(n) n u m num num表示查询时会修改的节点的数量,由于我们用最小值的方法建树,那么我们最多考虑到2倍的节点,总时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)级别的。

code

code on github

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值