int head, e[ N] , ne[ N] , idx;
void init ( )
{
head = - 1 ;
idx = 0 ;
}
void insert ( int a)
{
e[ idx] = a, ne[ idx] = head, head = idx ++ ;
}
void remove ( )
{
head = ne[ head] ;
}
int e[ N] , l[ N] , r[ N] , idx;
void init ( )
{
r[ 0 ] = 1 , l[ 1 ] = 0 ;
idx = 2 ;
}
void insert ( int a, int x)
{
e[ idx] = x;
l[ idx] = a, r[ idx] = r[ a] ;
l[ r[ a] ] = idx, r[ a] = idx ++ ;
}
void remove ( int a)
{
l[ r[ a] ] = l[ a] ;
r[ l[ a] ] = r[ a] ;
}
int stk[ N] , tt = 0 ;
stk[ ++ tt] = x;
tt -- ;
stk[ tt] ;
if ( tt > 0 )
{
}
1. Ordinary queue:
int q[ N] , hh = 0 , tt = - 1 ;
q[ ++ tt] = x;
hh ++ ;
q[ hh] ;
if ( hh <= tt)
{
}
2. Circular Queue
int q[ N] , hh = 0 , tt = 0 ;
q[ tt ++ ] = x;
if ( tt == N) tt = 0 ;
hh ++ ;
if ( hh == N) hh = 0 ;
q[ hh] ;
if ( hh != tt)
{
}
常见模型:找出每个数左边离它最近的比它大/ 小的数
int tt = 0 ;
for ( int i = 1 ; i <= n; i ++ )
{
while ( tt && check ( stk[ tt] , i) ) tt -- ;
stk[ ++ tt] = i;
}
常见模型:找出滑动窗口中的最大值/ 最小值
int hh = 0 , tt = - 1 ;
for ( int i = 0 ; i < n; i ++ )
{
while ( hh <= tt && check_out ( q[ hh] ) ) hh ++ ;
while ( hh <= tt && check ( q[ tt] , i) ) tt -- ;
q[ ++ tt] = i;
}
求模式串的Next数组:
for ( int i = 2 , j = 0 ; i <= m; i ++ )
{
while ( j && p[ i] != p[ j + 1 ] ) j = ne[ j] ;
if ( p[ i] == p[ j + 1 ] ) j ++ ;
ne[ i] = j;
}
for ( int i = 1 , j = 0 ; i <= n; i ++ )
{
while ( j && s[ i] != p[ j + 1 ] ) j = ne[ j] ;
if ( s[ i] == p[ j + 1 ] ) j ++ ;
if ( j == m)
{
j = ne[ j] ;
}
}
int son[ N] [ 26 ] , cnt[ N] , idx;
void insert ( char * str)
{
int p = 0 ;
for ( int i = 0 ; str[ i] ; i ++ )
{
int u = str[ i] - 'a' ;
if ( ! son[ p] [ u] ) son[ p] [ u] = ++ idx;
p = son[ p] [ u] ;
}
cnt[ p] ++ ;
}
int query ( char * str)
{
int p = 0 ;
for ( int i = 0 ; str[ i] ; i ++ )
{
int u = str[ i] - 'a' ;
if ( ! son[ p] [ u] ) return 0 ;
p = son[ p] [ u] ;
}
return cnt[ p] ;
}
( 1 ) 朴素并查集:
int p[ N] ;
int find ( int x)
{
if ( p[ x] != x) p[ x] = find ( p[ x] ) ;
return p[ x] ;
}
for ( int i = 1 ; i <= n; i ++ ) p[ i] = i;
p[ find ( a) ] = find ( b) ;
( 2 ) 维护size的并查集:
int p[ N] , size[ N] ;
int find ( int x)
{
if ( p[ x] != x) p[ x] = find ( p[ x] ) ;
return p[ x] ;
}
for ( int i = 1 ; i <= n; i ++ )
{
p[ i] = i;
size[ i] = 1 ;
}
size[ find ( b) ] + = size[ find ( a) ] ;
p[ find ( a) ] = find ( b) ;
( 3 ) 维护到祖宗节点距离的并查集:
int p[ N] , d[ N] ;
int find ( int x)
{
if ( p[ x] != x)
{
int u = find ( p[ x] ) ;
d[ x] + = d[ p[ x] ] ;
p[ x] = u;
}
return p[ x] ;
}
for ( int i = 1 ; i <= n; i ++ )
{
p[ i] = i;
d[ i] = 0 ;
}
p[ find ( a) ] = find ( b) ;
d[ find ( a) ] = distance;
int h[ N] , ph[ N] , hp[ N] , size;
void heap_swap ( int a, int b)
{
swap ( ph[ hp[ a] ] , ph[ hp[ b] ] ) ;
swap ( hp[ a] , hp[ b] ) ;
swap ( h[ a] , h[ b] ) ;
}
void down ( int u)
{
int t = u;
if ( u * 2 <= size && h[ u * 2 ] < h[ t] ) t = u * 2 ;
if ( u * 2 + 1 <= size && h[ u * 2 + 1 ] < h[ t] ) t = u * 2 + 1 ;
if ( u != t)
{
heap_swap ( u, t) ;
down ( t) ;
}
}
void up ( int u)
{
while ( u / 2 && h[ u] < h[ u / 2 ] )
{
heap_swap ( u, u / 2 ) ;
u >>= 1 ;
}
}
for ( int i = n / 2 ; i; i -- ) down ( i) ;
( 1 ) 拉链法
int h[ N] , e[ N] , ne[ N] , idx;
void insert ( int x)
{
int k = ( x % N + N) % N;
e[ idx] = x;
ne[ idx] = h[ k] ;
h[ k] = idx ++ ;
}
bool find ( int x)
{
int k = ( x % N + N) % N;
for ( int i = h[ k] ; i != - 1 ; i = ne[ i] )
if ( e[ i] == x)
return true ;
return false ;
}
( 2 ) 开放寻址法
int h[ N] ;
int find ( int x)
{
int t = ( x % N + N) % N;
while ( h[ t] != null && h[ t] != x)
{
t ++ ;
if ( t == N) t = 0 ;
}
return t;
}
核心思想:将字符串看成P进制数,P的经验值是131 或13331 ,取这两个值的冲突概率低
小技巧:取模的数用2 ^ 64 ,这样直接用unsigned long long 存储,溢出的结果就是取模的结果
typedef unsigned long long ULL;
ULL h[ N] , p[ N] ;
p[ 0 ] = 1 ;
for ( int i = 1 ; i <= n; i ++ )
{
h[ i] = h[ i - 1 ] * P + str[ i] ;
p[ i] = p[ i - 1 ] * P;
}
ULL get ( int l, int r)
{
return h[ r] - h[ l - 1 ] * p[ r - l + 1 ] ;
}
Introduction to C++ STL
vector, 变长数组,倍增的思想
size ( ) 返回元素个数
empty ( ) 返回是否为空
clear ( ) 清空
front ( ) / back ( )
push_back ( ) / pop_back ( )
begin ( ) / end ( )
[ ]
支持比较运算,按字典序
pair< int , int >
first, 第一个元素
second, 第二个元素
支持比较运算,以first为第一关键字,以second为第二关键字(字典序)
string,字符串
size ( ) / length ( ) 返回字符串长度
empty ( )
clear ( )
substr ( 起始下标,( 子串长度) ) 返回子串
c_str ( ) 返回字符串所在字符数组的起始地址
queue, 队列
size ( )
empty ( )
push ( ) 向队尾插入一个元素
front ( ) 返回队头元素
back ( ) 返回队尾元素
pop ( ) 弹出队头元素
priority_queue, 优先队列,默认是大根堆
size ( )
empty ( )
push ( ) 插入一个元素
top ( ) 返回堆顶元素
pop ( ) 弹出堆顶元素
定义成小根堆的方式:priority_queue< int , vector< int > , greater< int >> q;
stack, 栈
size ( )
empty ( )
push ( ) 向栈顶插入一个元素
top ( ) 返回栈顶元素
pop ( ) 弹出栈顶元素
deque, 双端队列
size ( )
empty ( )
clear ( )
front ( ) / back ( )
push_back ( ) / pop_back ( )
push_front ( ) / pop_front ( )
begin ( ) / end ( )
[ ]
set, map, multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列
size ( )
empty ( )
clear ( )
begin ( ) / end ( )
++ , -- 返回前驱和后继,时间复杂度 O ( logn)
set/ multiset
insert ( ) 插入一个数
find ( ) 查找一个数
count ( ) 返回某一个数的个数
erase ( )
( 1 ) 输入是一个数x,删除所有x O ( k + logn)
( 2 ) 输入一个迭代器,删除这个迭代器
lower_bound ( ) / upper_bound ( )
lower_bound ( x) 返回大于等于x的最小的数的迭代器
upper_bound ( x) 返回大于x的最小的数的迭代器
map/ multimap
insert ( ) 插入的数是一个pair
erase ( ) 输入的参数是pair或者迭代器
find ( )
[ ] 注意multimap不支持此操作。 时间复杂度是 O ( logn)
lower_bound ( ) / upper_bound ( )
unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表
和上面类似,增删改查的时间复杂度是 O ( 1 )
不支持 lower_bound ( ) / upper_bound ( ) , 迭代器的++ ,--
bitset, 圧位
bitset< 10000 > s;
~ , & , | , ^
>> , <<
== , !=
[ ]
count ( ) 返回有多少个1
any ( ) 判断是否至少有一个1
none ( ) 判断是否全为0
set ( ) 把所有位置成1
set ( k, v) 将第k位变成v
reset ( ) 把所有位变成0
flip ( ) 等价于~
flip ( k) 把第k位取反