树状数组
特别注意,树状数组下标为0是不可用的,若调用,记得加上偏移量!
求逆序对
用树状数组来记录
a
[
i
]
a[i]
a[i]出现了几次,然后没次根据不同需要,选择循环顺序以及
a
s
k
ask
ask求什么,最后把
a
[
i
]
a[i]
a[i]出现的次数+1
前面的数:正序循环
后面的数:倒序循环
比当前这个数小/大:
a
s
k
(
a
[
i
]
−
1
)
/
a
s
k
(
m
a
x
x
)
−
a
s
k
(
a
[
i
]
)
ask(a[i]-1)/ask(maxx)-ask(a[i])
ask(a[i]−1)/ask(maxx)−ask(a[i])
经典例题:
楼兰图腾
求顺序
大意是告诉你前面有几个人,问你他是第几个
假如一共有n个人,他前面有k个人,那么就让他站到第k+1个没有人的位置,至于这个位置怎么找,那么就要用上树状数组了,来维护前i个位置有多少个位置没人
经典例题:
L
o
s
t
C
o
w
s
Lost Cows
LostCows
B
u
y
T
i
c
k
e
t
s
Buy Tickets
BuyTickets
二维数点问题
诶嘿,树状数组可以上二维,具体思想其实就是一个前缀和
例如:求以
(
a
,
b
)
(a,b)
(a,b)为左下角,
(
c
,
d
)
(c,d)
(c,d)为右上角的矩形内的点,可以变成
s
u
m
[
c
]
[
d
]
−
s
u
m
[
a
−
1
]
[
d
]
−
s
u
m
[
c
]
[
b
−
1
]
+
s
u
m
[
a
−
1
]
[
b
−
1
]
sum[c][d]-sum[a-1][d]-sum[c][b-1]+sum[a-1][b-1]
sum[c][d]−sum[a−1][d]−sum[c][b−1]+sum[a−1][b−1]
在此基础上我们利用求逆序对得到的循环规则,用树状数组求解
首先把x排序,这样就可以减少一个影响啦
然后要找的就是当
x
=
a
x=a
x=a时
y
<
d
,
y
<
b
y<d,y<b
y<d,y<b的数量,当
x
=
c
x=c
x=c时
y
<
b
,
y
<
d
y<b,y<d
y<b,y<d的数量,用四倍的空间存起来,最后输出答案做个前缀和
所以这是个离线查询哒
经典例题:
园丁的烦恼(板子)
基因序列(这个是和trie树结合,巧妙地运用树的dfn序,进行二维数点)
地道战(把曼哈顿距离转换成切比雪夫距离就可以进行二维数点板子题啦)
前缀后缀求和
这算是树状数组的基础应用,和其他算法结合非常巧妙,当看到<=,>=之类的时候要想到利用树状数组
经典例题:
[SPOJ1825]免费旅行II(在点分治的基础上,运用树状数组进行答案统计)
笛卡尔树
用单调栈实现建树,每棵树满足:根为该子树最小值,且左子树的遍历编号<根<右子树
具体可参见:笛卡尔树
- 区间最小值可以考虑一下下哦
经典例题:
修数据
鲤鱼跃龙门 - 毕竟是用单调栈建树,单调栈能干的,它也可以
经典例题:
L a r g e s t R e c t a n g l e i n a H i s t o g r a m Largest Rectangle in a Histogram LargestRectangleinaHistogram
优先队列
排序
做模拟题的时候很容易让排序找最优解,这时候就能用到堆,当然,重载运算符别忘了怎么写,这里给出代码
struct node
{
int x,y,z;
friend bool operator < (node a1,node a2)//这里只能写<
{
return a1.x<a2.y;//这里的符号和真实情况相反,<即为大的在上,>即为小的在上
}
}
priority_queue<node> q;
经典例题:
模拟交易(太恶心了这题)
可后悔的贪心
如果贪心的时候发现前面的不对了,那么就可以撤销前面一个对结果影响最小的选择,这时候可以直接用堆排序,每次选择完都扔进去,然后就ok了
经典例题:
赌王
作业规划
并查集
模型转换
这个就比较明显了,看到什么谁和谁有关系,就应该往并查集上面去想,还有就是比较不明显的,需要把实在的物体抽象,然后通过每一组的特点进行合并计算
经典例题:
一维弹球(这道题,把球抽象成线段,机关抽象成点,通过两者之间的关心做题,实在是高啊)
同样,这道题也告诉我们,要学会排除或转化题目中没有用的条件,这道题把相互碰撞省掉了(想象成两个球交叉过去走)
例:神奇口袋(一个式子,让题目中给出的
x
,
y
x,y
x,y全没用,太强了)
直接跳过某些点
在进行暴力遍历的时候,可能会遍历到一个点多次,不需要,用一个bool数组标记直接跳过,但是还是会遍历到,复杂度依然很高,这时候就能用并查集了!把这些已经遍历过的点全部合并,之后就遍历不到它了,复杂度大大降低!【滑稽】
经典例题:
F
r
o
g
T
r
a
v
e
l
e
r
Frog\;Traveler
FrogTraveler(对于每一个位置,青蛙可能会有多种方式跳到,因为要求的是到达地面的最小天数,如果之前已经跳过了,再跳到相同的位置会浪费天数,所以,第一次是最优的,后面就不管这个点了,于是我们使用并查集,在跳过之后把它并掉就ok了)
清扫积雪 (上题是线性,这个上树了,但是他们的路线是固定的,依然是线性的,值得注意的是,题目中给的是bfs序,求LCA的时候不用再默板子了)
作业规划 (贪心+并查集优化)
trie
可删除
就是给每个节点一个siz,添加的时候siz++,删除的时候siz–,然后在找最大值的时候判断siz是否为空,很巧妙的一个思想
经典例题:
x
o
r
o
n
t
r
e
e
xor \;on\; tree
xorontree
第二种类型是差不多真的可删除,确实就像可删除线性基一样