csp复习笔记?


title: csp算法模板


线性筛素数

void sieve(){
    fill(isprime+1,isprime+n,true);
    for( int i = 2 ; i <= N ; i ++){
        if(isprime[i])
            prime[ ++ num ] = 2;
       	for(int j = 1 ; j <= num && i * prime[ j ] <= N ; j ++){
            isprime[ i * prime[ j ] ] = false;
            // smallest_prime[ i * prime[ j ] ] = prime[ j ] ;
            if( i % prime[ j ] == 0 )
                break;
        }
    }
}

树状数组

void add(int x , int v ){
    for(int i = x ; i <= N ; i += lowbit(i) ){
        tr[i] += v;
    }
}
void get_sum( int x ){//1到x
    int sum = 0;
    while(x){
        sum += tr[x];
        x -= lowbit(x);
    }
    return x;
}
/*************/
//区间求和,单点修改
for(int i = 1 ; i <= N ; i ++ ){
    add(i , a[i] );
}
get_sum(x);
add( x , v );//1到x
/**************/
//单点求和,区间修改,差分,a[i]=a[i]-a[i-1]
get_sum(x)+a[x];
add( x , v );
add( y + 1 , -v );
/*************/

单源最短路-Dijkstra

struct for_dij{
    int to,v;
    bool operator <(const for_dij &b) const {//堆默认是大根堆,因此重载<要反过来,堆内部实现只用了小于号
        return b.v < v;
    }
};
struct node{
    int to, w;
};
vector <node> edge[N];
bool book[N];
int dis[N];
void dijkstra(int a){
    memset(book,0,sizeof book);
    fill(dis+1,dis+n,0x7fffffff);
    priority_queue <for_dij> q;//堆优化
    q.push((for_dij){a,0});
    dis[a]=0;
   /*****************核心*****/
    while(!q.empty()){
        int u = q.top().to,value=q.top().v; q.pop();
        if(dis[u]!=value)//很重要的优化,剪掉“过时”的点
            continue;
        book[u]=true;
        for(int i = 0 ; i < edge[u].size(); i ++){
            int v =edge[u][i].to,w=edge[u][i].w;
            if(book[v]) continue;
            if( dis[v]>dis[u]+w){
                dis[v] = dis[u] + w;
                q.push((for_dij){v,dis[v]});
            }
        }
    }
    /******************/
}
for(int i = 1 ; i <= m ; i ++ ){
    int u,v,w;
    cin>>u>>v>>w;
    edge[u].push_back((node){v,w});
    edge[v].push_back((node){u,w});//双向
}

矩阵快速幂

//用于优化递推,dp
struct matrix{
    int g[N][N];
    matrix(){
        memset(g,0,sizeof g);
    }
    matrix operator *(const matrix &a) const{
        matrix c;
        for(int k = 1 ; k <= N ; k ++ )
            for(int i = 1; i <= N ; i ++ )
               	for(int j = 1; j <= N ; j ++ )
                    c.g[i][j]=(c.g[i][j]+g[i][k]*a.g[k][j]%mod)%mod;
        return c;
    }
}S,E;
//E是初始矩阵
//S是用于递推的矩阵
matrix poww(k){
    while(k){
        if(k&1) E = E * S;
        k >>= 1;
        S = S * S;
    }
    return E;
}

单调队列

P1886滑动窗口

寻找窗口内最大元素,定义一个单调队列q,和下标数组p

  1. 队列外的元素a与队列尾部元素b比较大小(队列为空时直接入队)

    • 若a>=b,则队尾元素出队
    • 若a<b,则a直接进队。
  2. 比较队首元素下标与窗口左端下标,队首元素出队直至队首元素下标>窗口左端下标

  3. 此时队首元素为该窗口内的最大元素

#define maxn 1001000
int q[ maxn ] , p[ maxn ] , n , k ,a[ maxn ];
int main ()
{
	ios::sync_with_stdio( false ) ;
	cin >> n >> k ;
	head = 1 , tail = 0 ; cout << endl ;
	for ( int i = 1 ; i <= n ; i ++ )
	{
		while ( head <= tail && q[ tail ] < a[ i ] )
			tail -- ;
		q[ ++ tail ] = a[ i ] ;
		p[ tail ] = i ;//以上对应步骤1
		while ( p[ head ] <= i - k ) head ++ ;//将队列下标与窗口左端对齐,对应步骤2
		if ( i >= k ) cout << q[ head ] << ' ' ;
	}
}

并查集

int find(a){
    if(fa[a]!=a) fa[a]=find(fa[a]);//路径压缩
    return a;
}
void merge(int a,int b){
    a= find(a);b=find(b);
    fa[a]=b;
}

最小生成树

prim

//本质上核dijkstra没区别
void prim(int a){
    memset(book,0,sizeof book);
    fill(dis+1,dis+n,0x7fffffff);
    priority_queue <for_dij> q;//堆优化
    q.push((for_dij){a,0});
    dis[a]=0;
   /*****************核心*****/
    while(!q.empty()){
        int u = q.top().to,value=q.top().v; q.pop();
        if(dis[u]!=value)//很重要的优化,剪掉“过时”的点
            continue;
        book[u]=true;
        mst += dis[u];//mst求最小生成树的所有边权
        for(int i = 0 ; i < edge[u].size(); i ++){
            int v =edge[u][i].to,w=edge[u][i].w;
            if(book[v]) continue;
            if( dis[v]>dis[u]+w){
                dis[v] = w;//除了原点,每个点存个最小生成树的边
                q.push((for_dij){v,dis[v]});
            }
        }
    }
    /******************/
}

最近公共祖先

//***********//链式前向星
struct node{
    int to , nex;
}edge[ m * 2 ];//双向路径边变两倍
void add_side( int u , int v , int w ){
    edge[ ++ num ] = { v , hea[ u ], w };
    hea[ u ] = num ;
    edge[ ++ num ] = { u , hea[ v ], w };
    hea[ v ] = num ;
}
void init( int s ){
    dep[ s ] = 1 ;
    for(int i = 2 ; i <= n ; i ++ )
        lg[ i ] = lg[ i - 1 ] + ( 1 << lg[ i - 1 ] == i - 1 ) ;
}
void dfs( int u ){//算是预处理吧
    for( int i = hea[ u ] ; i ; i = edge[ i ].nex ){
        int v = edge[ i ].to ;
        if( dep [ v ]) continue ;
        dep[ v ] = dep[ u ] + 1;
        f[ v ][ 0 ] = u ;
        for( int j = 1 ; j <= lg[ dep[ v ] ] ; j ++ )
            f[ v ][ j ] = f[ f[ v ][ j - 1 ] ][ j - 1 ] ;
        dfs( v ) ; 
    }
}
int lca( int a , int b ){
    if( dep[ a ] < dep[ b ] )
        swap( a , b );
    while( dep[ a ] > dep[ b ])
        a = f[ a ][ lg[ dep[ a ] - dep [ b ] ] ] ;
    if( a == b ) return a ;
    for( int k = lg[ dep[ a ] ] ; k >= 0 ; k -- ){
        if( f[ a ][ k ] != f[ b ][ k ] )
            a = f[ a ][ k ], b = f[ b ][ k ];
    }
    return f[ a ][ 0 ];
}

原文地址:https://www.cnblogs.com/nothatdinger/p/13649642.html