catalog
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] >