Algo_template算法模板

这篇博客介绍了算法模板,包括合并不重叠区间、筛质数、并查集、树状数组、取模运算、最大流与最小流问题、建图无权图和有权图的示例,以及Dijkstra算法、快速幂、最长单调子序列和Dinic最大流的应用。
摘要由CSDN通过智能技术生成

Algo

合并不重叠区间

此时sett里有:[1,2] [4,5] [8, 10] [12, 15]
新insert了一个:[6,7]
则他会变成:[1,2] [4,10] [12,15]

你必须确保,你所有调用的insert函数,任意两个区间 都是不重叠的!!!

template <typename Type>
class MergeInternal {
   
    
public:
    class Internal{
   
    public:
        Type l;
        Type r;

        explicit Internal( Type _l, Type _r) :
                l( _l),
                r( _r) {
   }

        bool operator<( const Internal & _i) const{
   
            
            if( _i.l == MergeInternal::MinFlag){
   
                return r < _i.r;
            }
            if( l != _i.l){
   
                return l < _i.l;
            }
            return r < _i.r;
        }
    };
    
    static Type MinFlag;
    
    set< Internal> sett;
    
public:
    MergeInternal(){
   
        
        if( TYPE(Type) == TYPE(int)){
   
            MinFlag = INT_80;
        }
        else if( TYPE(Type) == TYPE(LL)){
   
            MinFlag = LL_80;
        }
        else{
   
            EXIT;
        }
        
        sett.clear();
    }
    
    //  尝试与左右相邻区间,进行合并
    void insert( const Internal & _i){
   

        auto _l = sett.lower_bound( Internal(MergeInternal::MinFlag, _i.l - 1) );
        if( (_l != sett.end()) && (_l->r == (_i.l - 1)) ){
   
            int ll = _l->l;
            auto _r = sett.lower_bound( Internal(_i.r + 1, MergeInternal::MinFlag) );
            if( (_r != sett.end()) && (_r->l == (_i.r + 1)) ){
   
                int rr = _r->r;
                sett.erase(_l); 
                sett.erase(_r);
                sett.insert( Internal(ll, rr));
            }else{
   
                sett.erase(_l);
                sett.insert( Internal(ll, _i.r));
            }
        }else{
   
            auto _r = sett.lower_bound( Internal(_i.r + 1, MergeInternal::MinFlag) );
            if( (_r != sett.end()) && (_r->l == (_i.r + 1)) ){
   
                int rr = _r->r;
                sett.erase(_r);
                
                sett.insert( Internal(_i.l, rr));
            }else{
   
                sett.insert( _i );
            }
        }
    }
};
template <typename Type> Type MergeInternal<Type>::MinFlag;

筛质数(最大/小 的质因子)

class Prime_Sieve{
   
public:
	int N;
	int Count;
	std::vector<int> Prime;
	std::vector<bool> NotPrime;
	std::vector<int> MaxFact;
	std::vector<int> MinFact;
	
	Prime_Sieve( int _N ) : N(_N) {
   
		Prime = std::vector<int>(N); 
		// Prime的大小N可以变小,[1-N]范围内的质数 到不了N
		
		NotPrime= std::vector<bool>(N, false);
		NotPrime[0] = NotPrime[1] = true;
		// NotPrime[i] = true: i“不是”质数
		
		Count = 0;
		
		MaxFact = std::vector<int>(N);
		MinFact = std::vector<int>(N);
		
		for(int i = 2; i < N; ++i){
   
			if( !NotPrime[i] ){
   
				Prime[ Count ++ ] = i;
				MaxFact[i] = i;
				MinFact[i] = i;
			}
			for(int j = 0; Prime[j] * i < N; ++j){
   
				NotPrime[ Prime[j] * i ] = true;
				MaxFact[ Prime[j] * i ] = MaxFact[i];
				MinFact[ Prime[j] * i ] = Prime[j];
				if( i % Prime[j] == 0 ){
    break; }
			}
		}
	}
};

Demo

Prime_Sieve s(n);
auto ret = s.Prime[a]; // {0 <= a < s.Count}
auto ret = s.NotPrime[a]; // {0 <= a < n}
auto ret = s.MaxFact[a]; // {2 <= a < n}

并查集

class UnionFind{
   
public:
    std::vector<int> Fa;
    int N;
    UnionFind( int _N ) : N(_N){
   
        Fa = std::vector<int>(N);
        for(int i = 0; i < N; ++i){
   
            Fa[i] = i;
        }
    }
    int Find( int _T ){
   
        while( _T != Fa[_T] ){
   
            Fa[_T] = Fa[ Fa[_T] ];
            _T = Fa[_T];
        }
        return _T;
    }
    void Merge( int _T1, int _T2 ){
   
        int f1 = Find(_T1), f2 = Find(_T2);
        if( f1 == f2 ){
    return; }
        Fa[ f1 ] = f2;
    }
};

Demo

UnionFind u(n);
u.Merge(a, b); // {0 <= a,b < n}
auto fa = u.Find(a); // {0 <= a < n}

树状数组

class FenWick{
   
public:
	std::vector<int> Tr;
	int N;
	
	FenWick( int _N ) : N(_N){
   
		Tr = std::vector<int>(N, 0);
	}
	
	void Add( int _Pos, int _Val ){
   
		for(int i = _Pos; i < N; i += (i & -i)){
   
			Tr[i] += _Val;
		}
	}
	
	int Get_Sum( int _Pos ){
   
		// 获取[1,2,..._Pos]的前缀之和。
		int sum = 0;
		for(int i = _Pos; i > 0; i -= (i & -i)){
   
			sum += Tr[i];
		}
		return sum;
	}
};

Demo

FenWick f(n); 
f.Add(a, v); // {1 <= a < n}
auto ret = f.Get_Sum(a); // {0 <= a < n}

取模get_mod

long long GET_MOD(long long _a, long long _mod){
   
	// 注意: GET_MOD(a,b),并不会修改a的值!! 需要写成:a = GET_MOD(a,b)
    return (_a % _mod + _mod) % _mod;
}

有源汇-有上下界-最大流

n个点,m个单向边 每条边{low, hig},起点s,终点t。
求从起点s 到 终点t 的 最大 可行流。 (如果没有,返回-1)

cin >> n >> m >> s >> t;
FOR(i, 1, m + 1, 1){
     // [a -> b] (low, hig)
	if(i == m + 1){
   
		a = t, b = s, low = 0, hig = INT_7F;
	}else{
   
		cin >> a >> b >> low >> hig;
	}
	
	// 构建: 循环流算法的 残留网络。
	delta[a] += low, delta[b] -= low;
	base_flow[ind] += low;
	add_edge(a, b, hig - low), add_edge(b, a, 0);
}

// 注意下这里!!! _index表示的是: 我们新增的{s -> t}这条边 
// 虽然我们只添加了: t -> s这条边。 但因为残留网络是双向边,注意 这个_index 是 {s -> t}这个方向,是反向的。
// 因为,这条边 是为了补充“循环流”。而原可行流 所有流量 都流到了t,对应在循环流中:需要再流回s!!! 
// 即:t -> s 是对应的循环流的方向。 因为图存的是“残留网络”,所以 t->s的流量,对应为: wth[s -> t]
int _index = ind - 1; 

// 以下,都是循环流算法。
FOR(i, 1, n, 1){
   
    delta[i] *= -1;
}
int beg = n + 1, ed = n + 1 + 1;
int _should_flow = 0;
FOR(i, 1, n, 1){
   
    if(delta[i] >
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值