Documentos de Académico
Documentos de Profesional
Documentos de Cultura
The Reference
2
LCA
.................................................................................................................
21
Convolución
Discreta
................................................................................
39
Ejemplo
LCA
................................................................................................
21
Tolerancia
a
flotantes
...............................................................................
39
Heavy-‐Light
Decomposition
..................................................................
22
Multiplicar
Matrices
..................................................................................
39
Grafos
Guanajuato
–
Ejemplo
................................................................
22
Josephus
Problem
......................................................................................
39
Ley
de
Seno
...................................................................................................
39
Flujos
......................................................................................................
24
Ley
de
Coseno
..............................................................................................
39
Emparejamiento
Bipartito
.....................................................................
24
Fórmula
de
Herón
......................................................................................
39
Flujo
Máximo
..............................................................................................
24
Inverso
modular
.........................................................................................
39
Edmonds
Karp
............................................................................................
24
Triángulo
de
pascal
...................................................................................
40
Dinic
...............................................................................................................
25
Combinatoria
...............................................................................................
40
Definiciones
Adicionales
........................................................................
25
Radio
incentro
............................................................................................
40
Emparejamiento
Bipartito
de
costo
MAX/MIN
...............................
26
Radio
circuncentro
....................................................................................
40
Flujo
Memoria
Optimizada(Dinic)
......................................................
27
Incentro
.........................................................................................................
40
Max-‐Flow
Min-‐Cost
...................................................................................
28
Definiciones
.................................................................................................
40
Estructuras
de
Datos
.........................................................................
29
Extra
.......................................................................................................
41
Sparse
Table
................................................................................................
29
Fórmula
de
los
caballos
...........................................................................
41
SegmentTree
Dinámico
...........................................................................
29
Precision
cout
..............................................................................................
41
Segment
Tree
(Single
U,
Range
Q)
.......................................................
30
Big
Integer
/
Java
.......................................................................................
41
Segment
Tree
Lazy
(Single
U,
Range
Q)
.............................................
30
Constructor
..................................................................................................
41
Estructura
Fenwick
Tree
........................................................................
31
Constantes
....................................................................................................
41
Pila
Incremental
........................................................................................
32
Métodos
.........................................................................................................
42
Strings
....................................................................................................
33
Primos
hasta
el
1000
................................................................................
42
Suffix
Array
..................................................................................................
33
Códigos
Rivas
.......................................................................................
42
KMP
................................................................................................................
33
Robbing
Gringotts
......................................................................................
42
Hashing
.........................................................................................................
34
Joutong
Travels
...........................................................................................
45
Minimum
Rotating
String
&
BinSearch
(
returns
first
inequality
LIS
NON-‐DECREASING
...............................................................................
46
index
)
...........................................................................................................
34
LIS
STRICTLY
INCREASING
......................................................................
47
Trie
.................................................................................................................
35
Unique
Path
.................................................................................................
47
Matemagias
..........................................................................................
36
File
Transmission
......................................................................................
49
Factores
Primos
.........................................................................................
36
Criba
..............................................................................................................
36
Factores
del
Factorial
..............................................................................
36
Exponenciación
Binaria
..........................................................................
36
Multiplicación
Binaria
.............................................................................
36
Euclides
Extendido
...................................................................................
37
Estructura
Fracción
..................................................................................
37
Eliminación
Gaussiana
............................................................................
37
Phi
de
Euler
.................................................................................................
37
Estructura
Complejo
................................................................................
38
Fast
And
Fourier
........................................................................................
38
Fast
And
Fourier
Invertida
.....................................................................
38
3
STL
Set
<set>:
set<T> S // O(1)
C++
S.insert(T) // O(log n)
S.erase(T) // O(log n)
Vector
<vector>:
S.count(T) // O(log n)
vector<T> V // O(1) set<T>::iterator low=S.lower_bound( val )//O(log n)
V.push_back(T) // O(1) S.upper_bound( val ) // O(log n)
V.pop_back() // O(1) S.size() // O(1)
V.erase( V.begin(), V.end() ) // O(n) S.clear() // O(n)
V.insert(i, T) // O(n) Map
<map>:
V.size() // O(1)
V.clear() // O(n) map<K, V> M // O(1)
V[i] // O(1) M[K] = V // O(log n)
M.count(K) // O(log n)
M.clear() // O(n)
Stack
<stack>:
Priority
Queue
<queue>:
stack<T> S // O(1)
S.push(T) // O(1) priority_queue<T> PQ // O(1)
S.pop() // O(1) PQ.push(T) // O(log n)
S.size() // O(1) PQ.pop() // O(log n)
S.top() // O(1) PQ.top() // O(1)
PQ.empty() // O(1)
Queue
<queue>:
Bit
Set
<bitset>:
4
Override
Comparison
Operator:
upper_bound(array, array + n, T) // O(log n)
struct T{ // Data upper_bound(vector.begin(), vector.end(), T)
bool operator <(T cmp) const{// Comparison
} set.lower_bound(T) // O(log n)
}; set.upper_bound(T) // O(log n)
Reverse:
reverse(array, array + n) // O(n)
reverse(vector.begin(), vector.end()) // O(n)
Fill:
fill(array, array + n, T); // O(n)
fill(vector.begin(), vector.end(), T); // O(n)
5
Geometría
double
Dot(const
Punto&
v,
const
Punto&
w)
// Definiciones iniciales. // Producto punto entre vectores v y w.
typedef long long Long; double Dot(const Punto& v, const Punto& w) {
return v.x * w.x + v.y * w.y;
const double ERROR = 1e-9; }
const double M_2PI = 2 * M_PI;
double
Cruz(const
Punto&
v,
const
Punto&
w)
// Tolerancia en flotantes. // Producto cruz entre vectores v y w.
bool Igual(double a, double b) { double Cruz(const Punto& v, const Punto& w) {
return fabs(a - b) < ERROR; return v.x * w.y - v.y * w.x;
} }
6
Punto
Escalar(const
Punto&
v,
double
s)
// Escalar un vector v por un factor s. pair<Punto,
Punto>
ParMasCercano(vector<Punto>
Punto Escalar(const Punto& v, double s) { P)
return Punto(v.x * s, v.y * s);
// Par de puntos mas cercanos en un conjunto de
}
puntos P.
pair<Punto, Punto> ParMasCercano(vector<Punto> P) {
Punto
Opuesto(const
Punto&
v)
// Si ya esta ordenado, no usar sort.
// Obtener vector opuesto. sort(P.begin(), P.end());
Punto Opuesto(const Punto& v) { set<Punto> rect;
return Punto(-v.x, -v.y); pair<Punto, Punto> par;
} int prev = 0; double delta = 1e9;
for (int i = 0; i < P.size(); ++i) {
double
Angulo(const
Punto&
v,
const
Punto&
w)
while (P[i].x - P[prev].x > delta)
rect.erase(Punto(P[prev].y,
// Angulo entre vectores v y w.
P[prev++].x));
double Angulo(const Punto& v, const Punto& w) {
set<Punto>::iterator it = rect.lower_bound(
return acos(Dot(v, w) / (Magnitud(v) *
Punto( P[i].y - delta, P[0].x));
Magnitud(w)));
for (; it != rect.end()
}
&& it->x <= P[i].y + delta; ++it) {
double dist = hypot(P[i].x - it->y,
int
ManoDerecha(const
Punto&
o,
const
Punto&
p,
P[i].y - it->x);
const
Punto&
q)
if (dist < delta)
delta = dist, par = make_pair(
// Test de mano derecha: CCW = 1, CW=-1,Colineal=0. Punto(it->y, it->x), P[i]);
int ManoDerecha(const Punto& o, const Punto& p, }
const Punto& q) { rect.insert(Punto(P[i].y, P[i].x));
double ccw = Cruz(Trasladar(o, p), }
Trasladar(o, q)); return par;
return Igual(ccw, 0)? 0: (ccw < 0)? -1: 1; // Alternativamente puede devolver delta.
} }
Estructura
Linea
// Linea en 2D.
// Si los puntos no aseguran coordenadas
// enteras usar version double. ¡CUIDADO!
// Verifiquen los tags <comment> <uncomment>
7
struct Linea { bool
PuntoEnRecta(const
Punto&
p,
const
Linea&
r)
Punto p, q;
Long a, b, c; // <comment/> // Saber si un punto p esta en la recta r.
//double a, b, c; // <uncomment/> bool PuntoEnRecta(const Punto& p, const Linea& r) {
Linea() : p(), q(), a(), b(), c() {} return !ManoDerecha(r.p, r.q, p);
Linea(Long A, Long B, Long C) }
: p(), q(), a(A), b(B), c(C) {
if (Igual(a, 0)) { bool
PuntoEnSegmento(constPunto
p,const
Linea&s)
c /= -b; b = -1; // Saber si un punto p esta en el segmento s.
p = Punto(0, c); bool PuntoEnSegmento(const Punto& p,
q = Punto(1, c); const Linea& s){
} else if (Igual(b, 0)) { return PuntoEnRecta(p, s) &&
c /= -a; a = -1; !(p < s.p || s.q < p);
p = Punto(c, 0); }
q = Punto(c, 1);
} else { bool
LineasParalelas(const
Linea&l,
const
Linea&m)
p = Punto(-c/a, 0);
q = Punto(-(b+c)/a, 1); // Saber si dos lineas l y m son paralelas.
} bool LineasParalelas(const Linea& l,
if (q < p) swap(p, q); const Linea& m) {
} return l.a == m.a && l.b == m.b; // <comment/>
Linea(const Punto& P, const Punto& Q) // <uncomment>
: p(P), q(Q), a(), b(), c() { //if (Igual(l.b, 0) || Igual(m.b, 0))
// Asegura p como punto menor. // return Igual(l.a, m.a) && Igual(l.b,m.b);
if (q < p) swap(p, q); //return Igual(l.a/l.b, m.a/m.b);
a = q.y - p.y; // </uncomment>
b = p.x - q.x; }
if (!a) c = p.y, b = -1;
else if (!b) c = p.x, a = -1; bool
LineasIguales(const
Linea&
l,
const
Linea&
m)
else { // Saber si dos lineas l y m son iguales.
// <comment> bool LineasIguales(const Linea& l, const Linea& m){
c = abs(__gcd(a, b)); return LineasParalelas(l, m) && Igual(l.c,m.c);
a /= c, b /= c; }
// </comment>
c = -a*p.x - b*p.y;
}
}
// ¡PELIGRO! Ordena por ecuacion de recta.
bool operator<(const Linea& cmp) const {
if (!Igual(a, cmp.a)) return a < cmp.a;
if (!Igual(b, cmp.b)) return b < cmp.b;
return Igual(c, cmp.c)? false: c < cmp.c;
}
};
8
bool
LineasPerpendiculares(
const
Linea&
l
,const
int
IntersecRectaSegmen(const
Linea&
r,
const
Linea&
m)
Linea&
s)
// Saber si dos lineas l y m son perpendiculares. // Saber si una recta r y un segmento s se
bool LineasPerpendiculares(const Linea& l, intersectan.
const Linea& m) { // No intersectan = 0, Interseccion en un punto= 1,
return (l.a == m.b && l.b == -m.a) || // Interseccion paralela en infinitos puntos = -1.
(m.a==l.b && m.b == -l.a); //<comment/> int IntersecRectaSegmen(const Linea& r,
// <uncomment> const Linea& s) {
//if (Igual(l.b, 0) || Igual(l.a, 0)) if (LineasIguales(r, s)) return -1;
// return Igual(l.a, m.b) && Igual(l.b,m.a); if (LineasParalelas(r, s)) return 0;
//return Igual(-l.a/l.b, m.b/m.a); int t1 = ManoDerecha(r.p, r.q, s.p);
// </uncomment> int t2 = ManoDerecha(r.p, r.q, s.q);
} return (t1 != t2)? 1: 0;
}
Linea
ParalelaEnPunto(
const
Linea&
l,
const
int
InterseccionSegmentos(const
Linea&
s,
const
Punto&
p)
// Obtener una linea paralela a l que pase por p. Linea&
t)
Linea ParalelaEnPunto(const Linea& l, // Saber si dos segmentos s y t se intersectan.
const Punto& p) { // No intersectan = 0, Interseccion en un punto =1,
return Linea(p, Punto(p.x - l.b, p.y + l.a)); // Interseccion paralela en infinitos puntos = -1.
} int InterseccionSegmentos(const Linea& s,
const Linea& t) {
Linea
PerpendicularEnPunto(const
Linea&
l,
const
int t1 = ManoDerecha(s.p, s.q, t.p);
int t2 = ManoDerecha(s.p, s.q, t.q);
Punto&
p)
if (t1 == t2) return t1? 0:
//Obtener una linea perpendicular a l que pase por (PuntoEnSegmento(s.p, t) ||
p. PuntoEnSegmento(s.q, t) ||
Linea PerpendicularEnPunto(const Linea& l, PuntoEnSegmento(t.p, s) ||
const Punto& p) { PuntoEnSegmento(t.q, s))? -1: 0;
return Linea(p, Punto(p.x + l.a, p.y + l.b)); return (ManoDerecha(t.p, t.q, s.p) !=
} ManoDerecha(t.p, t.q, s.q))? 1: 0;
}
int
InterseccionRectas(const
Linea&r,const
Linea&s)
// Saber si dos rectas r y s se intersectan.
// No intersectan = 0, Interseccion en un punto =1,
// Interseccion paralela en infinitos puntos = -1.
int InterseccionRectas(const Linea& r,
const Linea& s) {
if (LineasIguales(r, s)) return -1;
return LineasParalelas(r, s)? 0: 1;
}
9
Punto
PuntoInterseccion(const
Linea&
l,
const
double
DistanciaPuntoSegmento(const
Punto&
p,
Linea&
m)
//Obtener punto de interseccion entre lineas l y m. const
Linea&
s)
Punto PuntoInterseccion(const Linea& l, // Distancia entre un punto p y un segmento s.
const Linea& m) { double DistanciaPuntoSegmento(const Punto& p,
assert(!LineasParalelas(l, m)); const Linea& s) {
//Si son paralelas KABOOM! Punto proy = ProyeccionEnRecta(p, s);
if (Igual(l.a, 0)) return if (proy < s.p) return Distancia(s.p, p);
Punto((double)(l.c*m.b + m.c) / -m.a, l.c); if (s.q < proy) return Distancia(s.q, p);
double y = (double)(m.a*l.c - l.a*m.c) / return Distancia(proy, p);
(m.b*l.a - m.a*l.b); }
return Punto((double)(l.c + l.b * y)/ -l.a, y);
} double
DistanciaRectaRecta(const
Linea&
l,
const
Punto
ProyeccionEnRecta(const
Punto&
v,
const
Linea&
m)
// Distancia entre dos lineas l y m.
Linea&
r)
double DistanciaRectaRecta(const Linea& l,
// Obtener proyeccion del vector v en la recta r. const Linea& m) {
Punto ProyeccionEnRecta(const Punto& v, return LineasParalelas(l, m)?
const Linea& r) { DistanciaPuntoRecta(l.p, m): 0;
Punto a = Trasladar(r.p, v), }
b = Trasladar(r.p, r.q);
return Trasladar(Opuesto(r.p), double
DistanciaSegmenSegmen(const
Linea&
s,
Escalar(b,Dot(a, b)/pow(Magnitud(b), 2)));
} const
Linea&
r)
// Distancia entre dos segmentos s y r.
double
DistanciaPuntoRecta(const
Punto&
p,
const
double DistanciaSegmenSegmen(const Linea& s,
const Linea& r) {
Linea&
r)
if (InterseccionSegmentos(s, r)) return 0;
// Distancia entre un punto p y una recta r. return min(min(DistanciaPuntoSegmento(s.p, r),
double DistanciaPuntoRecta(const Punto& p, DistanciaPuntoSegmento(s.q, r)),
const Linea& r) { min(DistanciaPuntoSegmento(r.p, s),
return Distancia(ProyeccionEnRecta(p, r), p); DistanciaPuntoSegmento(r.q, s)));
} }
Definición
Polígono
// Un poligono es una serie de
// vertices conectados por aristas.
// P = p1 -> p2 -> p3 -> ... -> pn -> p1.
10
bool
PuntoEnPerimetro(const
Punto&
p,
const
int
AngleSummation(const
Punto&
p,
const
Poligono&
P)
Poligono&
P)
// Saber si un punto esta en el perimetro de un // Punto en poligono concavo por angle summation.
poligono. // En el perimetro = -1, Fuera = 0, Dentro = 1.
bool PuntoEnPerimetro(const Punto& p, int AngleSummation(const Punto& p,
const Poligono& P) { const Poligono& P) {
for (int i = 1; i < P.size(); ++i) { if (PuntoEnPerimetro(p, P)) return -1;
Punto l = min(P[i - 1], P[i]); double angulo = 0;
Punto r = max(P[i - 1], P[i]); for (int i = 1; i < P.size(); ++i)
if (ManoDerecha(l, r, p) == 0 && angulo += ManoDerecha(p, P[i - 1], P[i]) *
!(p < l || r < p)) return true; Angulo(Trasladar(p, P[i - 1]),
} Trasladar(p, P[i]));
return false; return (fabs(angulo) > M_PI)? 1: 0;
} }
11
Poligono
CercoConvexo(vector<Punto>
P)
bool
RectaCortaPoligono(
const
Linea&
r,
const
// Cerco convexo de un conjunto de puntos. Poligono&
P)
Poligono CercoConvexo(vector<Punto> P){
// Si ya esta ordenado, no usar sort. // Saber si una recta corta un poligono.
sort(P.begin(), P.end()); bool RectaCortaPoligono( const Linea& r,
Poligono arriba, abajo; const Poligono& P) {
for (int i = 0; i < P.size(); ++i) { for (int i = 0, prim = 0; i < P.size(); ++i) {
while (arriba.size() > 1) { int lado = ManoDerecha(r.p, r.q, P[i]);
int p = arriba.size() - 1; if (!lado) continue;
// Permitir colineales: <= if (!prim) prim = lado;
if (ManoDerecha(arriba[p - 1], else if (lado != prim) return true;
arriba[p], P[i]) < 0) break; }
arriba.pop_back(); return false;
} }
arriba.push_back(P[i]);
} vector<Poligono>
CortarPoligono(const
Poligono&
arriba.pop_back(); P,
const
Linea&
r)
for (int i = P.size() - 1; i >= 0; --i) {
while (abajo.size() > 1) { // Obtiene los poligonos resultantes de
int p = abajo.size() - 1; // cortar un poligono convexo con una recta.
// Permitir colineales: <= vector<Poligono> CortarPoligono(const Poligono& P,
if (ManoDerecha(abajo[p - 1], const Linea& r) {
abajo[p], P[i]) < 0) break; if (!RectaCortaPoligono(r, P))
abajo.pop_back(); return vector<Poligono>(1, P);
} int ind = 0;
abajo.push_back(P[i]); vector<Poligono> Ps(2);
} for (int i = 1; i < P.size(); ++i) {
arriba.insert(arriba.end(), Linea s(P[i - 1], P[i]);
abajo.begin(), abajo.end()); if (IntersecRectaSegmen(r, s)) {
return arriba; // Convex hull. Punto p = PuntoInterseccion(r, s);
} if (P[i - 1] == p) continue;
Ps[ind].push_back(P[i - 1]);
Ps[1 - ind].push_back(p);
Punto
Centroide(const
Poligono&
P)
Ps[ind].push_back(p);
// Centroide de un poligono. ind = 1 - ind;
Punto Centroide(const Poligono& P) { }
double x = 0, y = 0, k = 0; else Ps[ind].push_back(P[i - 1]);
for (int i = 1; i < P.size(); ++i) { }
double cruz = Cruz(P[i - 1], P[i]); Ps[0].push_back(Ps[0][0]);
x += cruz * (P[i - 1].x + P[i].x); Ps[1].push_back(Ps[1][0]);
y += cruz * (P[i - 1].y + P[i].y); return Ps;
k += cruz * 3; }
}
return Punto(x/k, y/k);
}
12
Estructura
Círculo
Punto
ProyPuntoCircunferencia(const
Punto&
p,
// Circulo en 2D. const
Circulo&
c)
struct Circulo {
Punto c; double r; // Proyecta un punto fuera de un circulo en su
Circulo() : c(), r() {} circunferencia.
Circulo(const Punto& C, double R) : c(C),r(R){} Punto ProyPuntoCircunferencia(const Punto& p,
bool operator<(const Circulo& cmp) const { const Circulo& c) {
if (!(c == cmp.c)) return c < cmp.c; Punto v = Trasladar(p, c.c);
return Igual(r, cmp.r)? false: r < cmp.r; double prop = DistanciaPuntoCirculo(p, c) /
} Magnitud(v);
}; return Trasladar(Opuesto(p), Escalar(v, prop));
}
double
Circuferencia(const
Circulo&
c)
Linea
ProyTangentes(const
Punto&
p,
const
// Circunferencia de un circulo.
double Circuferencia(const Circulo& c) { Circulo&
c)
return M_2PI * c.r; // Obtiene dos puntos que, desde el punto p, forman
} //lineastangentesa la circunferencia del circulo c.
Linea ProyTangentes(const Punto& p,
double
Area(const
Circulo&
c)
const Circulo& c) {
// Area de un circulo. double a = acos(c.r / Distancia(p, c.c));
double Area(const Circulo& c) { Punto p_ = Trasladar(c.c,
return M_PI * c.r * c.r; ProyPuntoCircunferencia(p, c));
} return Linea(Trasladar(Opuesto(c.c),
Rotar(p_, M_2PI - a)),
Trasladar(Opuesto(c.c),
int
PuntoEnCirculo(const
Punto&
p,const
Circulo&
c)
Rotar(p_, a)));
// Saber si un punto esta dentro de un circulo. }
// En circunferencia = -1, Fuera = 0, Dentro = 1.
int PuntoEnCirculo(const Punto& p,
const Circulo& c) {
int
IntersecCirculoRecta(const
Circulo&
c,
const
double dist = Distancia(p, c.c); Linea&
r)
if (Igual(dist, c.r)) return -1; // Saber si se intersecta un circuloC y una rectaR.
return (dist < c.r)? 1: 0; // Tangente = -1, No se intersectan = 0, Cuerda= 1.
} int IntersecCirculoRecta(const Circulo& c,
const Linea& r) {
double
DistanciaPuntoCirculo(const
Punto&
p,
const
double dist = DistanciaPuntoRecta(c.c, r);
if (Igual(dist, c.r)) return -1;
Circulo&
c)
return (dist < c.r)? 1: 0;
// Distancia de un punto p a un circulo c }
double DistanciaPuntoCirculo(const Punto& p,
const Circulo& c) {
double dist = Distancia(p, c.c) - c.r;
return (dist < 0)? 0: dist;
}
13
Punto
Chicharronera(double
a,
double
b,
double
c)
int
IntersecCirculoCirculo(const
Circulo&
c,
const
// Soluciones a ecuaciones cuadraticas. Circulo&
d)
Punto Chicharronera(double a, double b, double c) {
double sq = sqrt(b*b - 4*a*c); //Saber si circulo c intersecta con el circulo d.
return Punto((-b + sq) / (2*a), // Uno dentro del otro = -1, Disjuntos = 0,
(-b - sq) / (2*a)); Intersectan = 1.
} int IntersecCirculoCirculo(const Circulo& c,
const Circulo& d) {
double dist = Distancia(c.c, d.c);
Linea
CuerdaInterseccion(const
Circulo&
c,
const
if (dist < fabs(c.r - d.r)) return -1;
Linea&
r)
return (dist > c.r + d.r)? 0: 1;
}
//Cuerda de interseccion entre 1 circulo y 1 recta.
Linea CuerdaInterseccion(const Circulo& c,
const Linea& r) { int
TangenteExtCirculoCirculo
assert(IntersecCirculoRecta(c, r)); // KABOOM! // Obtiene tangentes exteriores (las que NO se
Punto p, q; cruzan) entre dos círculos.
if (!Igual(r.b, 0)) { Int TangenteExtCirculoCirculo(const Circulo& a,
Linea R = Linea(Trasladar(c.c, r.p), const Circulo& b, Linea &s, Linea &t) {
Trasladar(c.c, r.q)); // Circulos identicos. Tangentes infinitas (o
p = Chicharronera(R.a*R.a + R.b*R.b, ninguna a discrecion)
2*R.a*R.c, if (Igual(a.r, b.r) && a.c == b.c) return 0;
R.c*R.c - R.b*R.b*c.r*c.r); // Uno es círculo interior del otro. Comparten una
q = Punto(p.y, (R.c + R.a*p.y) / -R.b); tangente.
p.y = (R.c + R.a*p.x) / -R.b; // EL CALCULO PUEDE COPIARSE A TangenteInt SI SE
p = Trasladar(Opuesto(c.c), p); REQUIERE.
q = Trasladar(Opuesto(c.c), q); Punto u;
} bool unico = false;
else { if(b.r<a.r && Igual(Distancia(a.c, b.c)
double sq = sqrt(c.r*c.r – + b.r, a.r)){
pow(r.p.x - c.c.x, 2)); u = Trasladar(Opuesto(a.c),
p = Punto(r.p.x, c.c.y + sq); Escalar(Trasladar(a.c, b.c),
q = Punto(r.p.x, c.c.y - sq); a.r/Distancia(a.c, b.c)));
} unico = true;
return Linea(p, q); }
} if (a.r < b.r && Igual(Distancia(a.c, b.c)
+ a.r, b.r)) {
bool
CirculoEnCirculo(const
Circulo&
c,
const
u = Trasladar(Opuesto(b.c),
Escalar(Trasladar(b.c, a.c),
Circulo&
d)
b.r / Distancia(a.c, b.c)));
//Saber si 1 circulo c esta dentro de un circulo d. unico = true;
bool CirculoEnCirculo(const Circulo& c, }
const Circulo& d) { if (unico) {
return Distancia(c.c, d.c) < d.r - c.r; s = t = PerpendicularEnPunto(
} Linea(a.c, b.c), u);
14
// Recta de tangencia; un punto es referencia. // Uno es círculo interior del otro. Comparten una
//s = t = Linea(u, u); // Punto de tangencia. tangente.
return 1; // CALCULO HECHO EN TangenteInt. Copiar de este si
} se requiere.
// Circulo en circulo. No hay tangentes. Punto u;
if (CirculoEnCirculo(a, b) || // Circulos tangentes. Obtener recta tangente
CirculoEnCirculo(b, a)) { unica.
return 0; if (Igual(Distancia(a.c, b.c), a.r + b.r)) {
} u = Trasladar(Opuesto(b.c),
// Calcular las 2 rectas tangentes. Escalar(Trasladar(b.c, a.c),
Linea proy; b.r / Distancia(a.c, b.c)));
Punto v; s = t = PerpendicularEnPunto(
if (Igual(a.r, b.r)) { Linea(a.c, b.c), u);
proy = Linea(a.c, a.c); // Recta de tangencia.
Linea perp = PerpendicularEnPunto( //s = t = Linea(u, u);
Linea(a.c, b.c), a.c); // Punto de tangencia.
u = Escalar(Trasladar(perp.q, perp.p), return 1;
b.r / Distancia(perp.p, perp.q)); }
v = Opuesto(u); // Circulos se traslapan. no hay tangentes.
} else { if (!(a.r + b.r < Distancia(a.c, b.c)))
Circulo c(a.c, abs(a.r - b.r)); return 0;
proy = ProyTangentes(b.c, c); // Obtener 2 rectas tangentes.
u = Escalar(Trasladar(a.c, proy.p), Linea proy;
b.r / (a.r - b.r)); Punto v;
v = Escalar(Trasladar(a.c, proy.q), Circulo c(a.c, a.r + b.r);
b.r / (a.r - b.r)); proy = ProyTangentes(b.c, c);
} u = Escalar(Trasladar(a.c, proy.p),
s = Linea(Trasladar(Opuesto(proy.p), u), b.r / (a.r + b.r));
Trasladar(Opuesto(b.c), u)); v = Escalar(Trasladar(a.c, proy.q),
t = Linea(Trasladar(Opuesto(proy.q), v), b.r / (a.r + b.r));
Trasladar(Opuesto(b.c), v)); s =Linea(Trasladar(Opuesto(proy.p),Opuesto(u)),
return 2; Trasladar(Opuesto(b.c), Opuesto(u)));
} t =Linea(Trasladar(Opuesto(proy.q),Opuesto(v)),
Trasladar(Opuesto(b.c), Opuesto(v)));
int
TangenteIntCirculoCirculo
return 2;
}
// Obtiene tangentes interiores (las que SI se
cruzan) entre dos círculos.
int TangenteIntCirculoCirculo(const Circulo& a,
const Circulo& b, Linea &s, Linea &t) {
// Circulos identicos. Tangentes infinitas (o
ninguna a discrecion)
if (Igual(a.r, b.r) && a.c == b.c)
return 0
15
vector<
Punto
>
PuntosInterseccionCirculos(
const
Circulo&
c,
const
Circulo&
d
)
vector< Punto > PuntosInterseccionCirculos( const
Circulo& c, const Circulo& d ){
int mano;
vector<Punto> ret;
double angulo = 0.0, dist, X, Y;
Circulo C = Circulo( Punto( 0, 0 ), c.r );
Circulo D = Circulo(Trasladar( c.c, d.c ),d.r);
mano = ManoDerecha(Punto(0,0),Punto(1,0), D.c);
if( mano == 1 )
angulo = M_2PI - Angulo( Punto(1,0),D.c );
else if( mano == -1 )
angulo = Angulo( Punto( 1, 0 ), D.c );
D.c = Rotar( D.c, angulo );
dist = Distancia( D.c, C.c );
if( Igual( dist, C.r + D.r ) ){
ret.push_back( Punto( C.r, 0 ) );
ret[0] = Rotar( ret[0], M_2PI - angulo );
ret[0] = Trasladar(
Punto( -c.c.x, -c.c.y), ret[0] );
}
else if( dist < (C.r + D.r) &&
dist > fabs(C.r - D.r)) {
X = (dist*dist - D.r*D.r + C.r*C.r) /
(2*dist);
Y = sqrt( C.r*C.r - X*X );
ret.push_back( Punto( X, Y ) );
ret.push_back( Punto( X, -Y ) );
for( int i = 0; i < 2; i++ ){
ret[i] = Rotar( ret[i], M_2PI-angulo );
ret[i] = Trasladar( Punto( -c.c.x,
-c.c.y ), ret[i] );
}
}
return ret;
}
16
Grafos
if (color[u] == 'G' && color[v] == 'R')
color[u] = 'R', ciclo.push_back(u);
}
Definiciones
Iniciales
if (color[u] == 'G') color[u] = 'N';
typedef int Costo; }
typedef pair<int, int> Arista; vector<vector<int>> DetectarCiclos() {
const Costo INF = 1 << 30; vector<vector<int>> ciclos;
color = vector<char>(n, 'B');
for (int u = 0; u < n; ++u) {
Estructura
Grafo
if (color[u] != 'B') continue;
// Grafos no ponderados. ciclo.clear(); DetectarCiclo(u, n);
// Nodos indexados de 0 a n - 1. reverse(ciclo.begin(), ciclo.end());
// Grafo(n, true) -> Bidireccional. if (!ciclo.empty())
// Grafo(n, false) -> Dirigido. ciclos.push_back(ciclo);
struct Grafo { }
int n; bool bi; return ciclos;
vector<vector<int>> ady; }
Grafo(int N, bool B = true): n(N), bi(B),
ady(N) {} Puentes
y
Puntos
de
Articulación
void AgregarArista(int u, int v) {
// Deteccion de puentes y puntos de articulacion
if (bi) ady[v].push_back(u);
// en 1 grafo o multigrafo bidireccional.Los puentes
ady[u].push_back(v); // quedan guardados en un vector de aristas. Los puntos
} // de articulacion son marcados como true o false
// respectivamente en un vector de booleanos.
Detectar
Ciclos
int tiempo;
// Detecta ciclos en un grafo o multigrafo. vector<int> label, low;
// Llamar a DetectarCiclos() devuelve un vector<Arista> puentes; // <- Resultado
// vector de vectores; cada vector interno es vector<bool> articulacion; // <- Resultado
// una lista que representa un ciclo del grafo. int PuentesArticulacion(int u, int p) {
// NOTA: Solo detecta un ciclo por componente. label[u] = low[u] = ++tiempo;
vector<int> ciclo; int hijos = 0, retorno = 0;
vector<char> color; for (int v : ady[u]) {
void DetectarCiclo(int u, int p) { if (v == p && !retorno++) continue;
int retorno = bi? 0: 1; if (!label[v]) {
color[u] = ciclo.empty()? 'G': 'N'; ++hijos; PuentesArticulacion(v, u);
for (int v : ady[u]) { if (label[u] <= low[v])
if (v == p && !retorno++) continue; articulacion[u] = true;
if (ciclo.empty() && color[v] == 'G') { if (label[u] < low[v])
color[v] = 'A', ciclo.push_back(v); puentes.push_back(Arista(u, v));
if (u != v) color[u] = 'R', low[u] = min(low[u], low[v]);
ciclo.push_back(u); }
} low[u] = min(low[u], label[v]);
if (color[v] != 'B') continue; }
DetectarCiclo(v, u); return hijos;
}
17
void FuertementeConexo() {
void PuentesArticulacion() { low = vector<int>(n);
low = vector<int>(n); label = vector<int>(n);
label = vector<int>(n); tiempo = 0, scc.clear();
tiempo = 0, puentes.clear(); top = -1, pila = vector<int>(n);
articulacion = vector<bool>(n); for (int u = 0; u < n; ++u)
for (int u = 0; u < n; ++u) if (!label[u]) FuertementeConexo(u);
if (!label[u]) }
articulacion[u] =
PuentesArticulacion(u, n) > 1; EsBipartito
}
// Determina si un grafo bidireccional
// es bipartito (o bien, es bicoloreable).
Componentes
Fuertemente
Conexas
bool EsBipartito() {
// Deteccion de componentes fuertemente conexas vector<char> color(n, -1);
// en un grafo dirigido. Las componentes quedan for (int u = 0; u < n; ++u) {
// guardadas en un vector de vectores, donde if (color[u] >= 0) continue;
// cada vector interno contiene los nodos color[u] = 0;
// de una componente fuertemente conexa. queue<int> q; q.push(u);
vector<vector<int>> scc; // <- Resultado while (!q.empty()) {
int top; vector<int> pila; int u = q.front(); q.pop();
for (int v : ady[u]) {
void FuertementeConexo(int u) { if (color[v] < 0) q.push(v),
label[u] = low[u] = ++tiempo; color[v] = 1 - color[u];
pila[++top] = u; if (color[u] == color[v])
for (int v : ady[u]) { return false;
if (!label[v]) FuertementeConexo(v); }
low[u] = min(low[u], low[v]); }
} }
if (label[u] == low[u]) { return true;
vector<int> componente; }
while (pila[top] != u) {
componente.push_back(pila[top]); Orden
Topológico
low[pila[top--]] = n + 1;
// Obtiene el orden topologico de los nodos
}
// de un grafo dirigido. Orden ascendente
componente.push_back(pila[top--]);
// respecto al numero de dependencias.
scc.push_back(componente);
vector<bool> vis;
low[u] = n + 1;
vector<int> ordenados;
}
void OrdenTopologico(int u) {
}
vis[u] = true;
for (int v : ady[u])
if (!vis[v]) OrdenTopologico(v);
ordenados.push_back(u);
}
18
void OrdenTopologico() { void Unir(int u, int v) {
ordenados.clear(); int Ru = Raiz(u); int Rv = Raiz(v);
vis = vector<bool>(n); if (Ru == Rv) return;
for (int u = 0; u < n; ++u) --n, padre[Ru] = Rv;
if (!vis[u]) OrdenTopologico(u); tam[Rv] += tam[Ru];
} }
int Raiz(int u) {
if (padre[u] == u) return u;
return padre[u] = Raiz(padre[u]);
}
19
Kruskal
}
}
// Obtiene el arbol de expansion minima de un return dist;
// grafo bidireccional. Para obtener el arbol }
// de expansion maxima descomentar el reverse.
// En caso de tener varias componentes conexas,
// obtiene el bosque de expansion minima. BellmanFerrari
vector<Ponderada> Kruskal() { // Algoritmo de Bellman-Ford optimizado, desde
vector<Ponderada> todas; // el nodo s. Devuelve un booleano indicando si
for (int u = 0; u < n; ++u) // existe un ciclo negativo en un digrafo.
for (CostoNodo arista : ady[u]) // Obtiene el vector de distancias a todos.
todas.push_back(Ponderada(arista.first, vector<Costo> dist; // <- Resultado
Arista(u, arista.second))); bool BellmanFerrari(int s) {
sort(todas.begin(), todas.end()); queue<int> q;
// reverse(todas.begin(), todas.end()); vector<bool> en_cola(n);
vector<Ponderada> mst; vector<int> procesado(n);
UnionFind componentes(n); dist = vector<Costo>(n, INF);
for (Ponderada arista : todas) { q.push(s), dist[s] = 0;
int u = arista.second.first; while (!q.empty()) {
int v = arista.second.second; int u = q.front();
if (!componentes.SonConexos(u, v)) q.pop(), en_cola[u] = false;
componentes.Unir(u, v), if (++procesado[u] == n) return true;
mst.push_back(arista); for (CostoNodo arista : ady[u]) {
} int v = arista.second;
return mst; Costo p = arista.first;
} if (dist[u] + p < dist[v]) {
if (!en_cola[v]) q.push(v);
Dijkstra
dist[v] = dist[u] + p;
en_cola[v] = true;
// Algoritmo de dijkstra desde el nodo s. }
// Devuelve el vector de distancias a todos }
// los nodos desde s. Un valor INF indica que }
// no es posible ir de s al respectivo nodo. return false;
vector<Costo> Dijkstra(int s) { }
vector<Costo> dist(n, INF); }; //Fin estructura GrafoCosto
priority_queue<CostoNodo> pq;
pq.push(CostoNodo(0, s)), dist[s] = 0;
while (!pq.empty()) {
Costo p = -pq.top().first;
int u = pq.top().second; pq.pop();
if (dist[u] < p) continue;
for (CostoNodo arista : ady[u]) {
int v = arista.second;
p = dist[u] + arista.first;
if (p < dist[v]) dist[v] = p,
pq.push(CostoNodo(-p, v));
20
Árboles
for( int i = lg ; i >= 0 ; i-- ){
if( P[p][i] != -1 && P[p][i] != P[q][i]){
maxi = max( maxi, max( maximo[q][i],
LCA
maximo[p][i] ));
#define MAXV 105 p = P[p][i];
#define LOGV 10 q = P[q][i];
#define mp make_pair }
using namespace std; }
int level[ MAXV ], parent[ MAXV ], N; maxi = max(max( maximo[p][0], maxi ) ,
int P[ MAXV ][ LOGV ], maximo[ MAXV ][ LOGV ], maximo[q][0]);
peso[ MAXV ]; return maxi;
}
void PRE(){
for(int u = 0; u < N; u++){ Ejemplo
LCA
P[u][0] = parent[u]; int main(){
maximo[u][0] = peso[u]; int A, Q, B;
} lli L;
for(int i = 1; (1 << i) <= N; i++){ while( 1 ){
for(int u = 0; u < N; u++){ cin >> N;
P[u][i] = P[P[u][i-1]][i-1]; if( !N ) break;
maximo[u][i] = max( maximo[u][i - 1], for( int i = 0; i <= N; i++ ){
maximo[P[u][i - 1]][i - 1] ); dist[ i ] = 0;
} level[ i ] = 1;
} parent[ i ] = i;
} }
int LCA(int p , int q){ for( int i = 1; i < N; i++ ){
if(level[p] < level[q]) swap(p,q); cin >> A >> L;
int lg; parent[ i ] = A;
for( lg = 1 ; (1 << lg) <= level[p] ; ++lg ); dist[ i ] = ( L + dist[ A ] );
lg--; level[ i ] += level[ A ];
int maxi = 0; }
for( int i = lg ; i >= 0 ; i--){ PRE();
if( level[p] - (1 << i) >= level[q] ){ cin >> Q;
maxi = max( maxi, maximo[p][i] ); for( int i = 0; i < Q; i++ ){
p = P[p][i]; cin >> A >> B;
} if( i ) cout << ' ';
} cout << dist[ A ] + dist[ B ] –
if( p == q ) return maxi; ( 2ll * dist[ LCA( A, B ) ] );
}
cout << '\n';
}
}
21
Heavy-‐Light
Decomposition
for(int i = 0; i < aristas[u].size(); ++i){
int v = aristas[u][i];
// Definiciones iniciales. if (p == v) continue;
typedef vector<int> Lista; if (tamano[v] > tam_subarbol / 2)
indice[u] = indice[v] + 1,
// Arbol con Heavy-Light Decomposition. super[u] = super[v],
// Los nodos estan indexados de 0 a n - 1. top[super[v]] = u;
struct HeavyLight { }
int n, conteo; if (super[u] == -1)
Lista nivel, tamano, up; super[u] = conteo, top[conteo++] = u;
Lista indice, super, top; if (p == -1) CalcularNivel(u, p);
vector<Lista> aristas; return tamano[u] = tam_subarbol + 1;
HeavyLight(int N) : n(N), conteo(),top(N), }
nivel(N), tamano(N), up(N), indice(N), int LCA(int u, int v) {
super(N), aristas(N) {} if (nivel[v] > nivel[u]) swap(u, v);
while (nivel[u] > nivel[v])
void AgregarArista(int u, int v) { u = up[top[super[u]]];
aristas[u].push_back(v); while (super[u] != super[v])
aristas[v].push_back(u); u = up[top[super[u]]],
} v = up[top[super[v]]];
return (indice[u] > indice[v])? u: v;
void CalcularNivel(int u, int p) { }
for(int i = 0; i < aristas[u].size(); ++i){ };
int v = aristas[u][i];
if (p == v) continue;
if (super[u] == super[v]) Grafos
Guanajuato
–
Ejemplo
nivel[v] = nivel[u]; /* Ejemplo de Grafos guanajuato (Distancias
else nivel[v] = nivel[u] + 1; minimas):
CalcularNivel(v, u); MAXN - cantidad máxima de nodos
} LOGN - logaritmo base 2 de MAXN
} N - cantidad de nodos actual
// Construir realiza todas las operaciones para M - cantidad de aristas
// trabajar con Heavy-Light. Por defecto, la nxt[i] - continene el nodo con el que esta unido i
raiz del // arbol se establece como el nodo now - nodo con el que se inicia la busqueda del
0. Si quieren definir una raiz diferente, ciclo
llamen Construir(r) donde el parametro r indica cntc - conteo/’mapeo’/id’s de los ciclos
cual sera la raiz del arbol. Rciclo[i] - contiene el id del ciclo en el que esta
int Construir(int u = 0, int p = -1) { el nodo ‘i’ (si es que pertenece)
int tam_subarbol = 0; Tciclo[i] - contiene el numero de nodos en el ciclo
up[u] = p, super[u] = -1; con id ‘i’
for(int i = 0; i < aristas[u].size(); ++i){ Nciclo[i] - al numerar los nodos en un ciclo, este
int v = aristas[u][i]; arreglo contiene el numero que se le dio al nodo
if (p == v) continue; ‘i’ en el ciclo (si es que pertenece a uno)
tam_subarbol += Construir(v, u); Pciclo[i] - contiene la raiz (nodo que es parte de
} un ciclo) del arbol en el que esta el nodo ‘i’
22
P[][] - Arreglo para el preproceso y recorrido para int lca(int u, int v) {
LCA if (level[u] > level[v]) swap(u, v);
pfsvis[] - visitados para la pfs for (int i = 0, j = level[v]-level[u]; i < LOGN
vis[] - visitados de la dfs && j > 0; ++i, j >>= 1)
level[] - nivel del LCA */ if (j & 1) v = P[v][i];
const int MAXN = 100010, LOGN = 18; if (u == v) return u;
int N, M, nxt[MAXN], now, cntc, Rciclo[MAXN], for (int i = LOGN - 1; i >= 0; --i)
Tciclo[MAXN], Nciclo[MAXN], P[MAXN][LOGN], if (P[u][i] != P[v][i]) {
Pciclo[MAXN]; u = P[u][i];
int pfsvis[MAXN], vis[MAXN], level[MAXN]; v = P[v][i];
}
void pfs(int u) { return P[u][0];
pfsvis[u] = now; }
if (!pfsvis[nxt[u]]) pfs(nxt[u]); int dist(int u, int v) {
else if (pfsvis[nxt[u]] == now) { return level[u]+level[v]-(level[lca(u, v)]<<1);
Rciclo[u] = ++cntc; }
Tciclo[cntc] = 1; int main() {
Nciclo[u] = 1; while (cin >> N) {
for(int i=nxt[u], last=u; i!=u; last=i, cntc = 0;
i=nxt[i]){ memset(Rciclo, 0, sizeof Rciclo);
Rciclo[i] = Rciclo[last]; memset(level, 0, sizeof level);
Nciclo[i] = Nciclo[last] + 1; memset(pfsvis, 0, sizeof pfsvis);
Tciclo[cntc]++; memset(Nciclo, 0, sizeof Nciclo);
} memset(vis, 0, sizeof vis);
} for (int i = 1; i <= N; ++i)cin >> nxt[i];
} for (int i = 1; i <= N; ++i)if (!pfsvis[i])
void dfs(int u) { now = i, pfs(i);
vis[u] = 1; for(int i=1; i<=N; ++i) if(!vis[i]) dfs(i);
if (!Rciclo[u]) { PRE(); cin >> M;
P[u][0] = nxt[u]; for (int i = 0; i < M; ++i) {
if (!vis[nxt[u]]) dfs(nxt[u]); int u, v; cin >> u >> v;
Pciclo[u] = Pciclo[nxt[u]]; if(Rciclo[Pciclo[u]]!=Rciclo[Pciclo[v]])
level[u] = level[nxt[u]] + 1; cout << -1 << ‘\n‘;
} else if (Pciclo[u] == Pciclo[v])
else { cout << dist(u, v) << “\n”;
P[u][0] = 0; else {
Pciclo[u] = u; int tmp = abs(Nciclo[Pciclo[u]] –
level[u] = 0; Nciclo[Pciclo[v]]);
} tmp=min(tmp,Tciclo[Rciclo[Pciclo[u]]]–tmp);
} cout << level[u]+level[v]+tmp << “\n”;
void PRE() { }
for (int d = 1; d < LOGN; ++d) }
for (int i = 1; i <= N; ++i) }
P[i][d] = P[P[i][d - 1]][d – 1]; return 0;}
}
23
Flujos
vector<Par> MaxEmparejamiento() {
fill(pareja.begin(), pareja.end(), -1);
// Definiciones iniciales. for (int i = 0; i < n; ++i) {
typedef int Flujo; if (!lado[i]) continue;
// Ajustable. CaminoIncremental(i);
typedef vector<int> Lista; fill(visitado.begin(),
typedef pair<int, int> Par; visitado.end(), false);
typedef vector<Flujo> Flujo1D; }
typedef vector<Flujo1D> Flujo2D; vector<Par> pares;
const Flujo FINF = 1 << 30; for (int i = 0; i < n; ++i)
if (!lado[i] && pareja[i] != -1)
Emparejamiento
Bipartito
pares.push_back(Par(pareja[i], i));
// Nodos indexados de 0 a n - 1. return pares;//Cardinalidad =
struct Bipartito { pares.size()
int n; Lista pareja; }
vector<Lista> aristas; };
vector<bool> lado, visitado;
Bipartito(int N) : lado(N), pareja(N), Flujo
Máximo
visitado(N), aristas(N), n(N) {} // Nodos indexados de 0 a n - 1.
struct GrafoFlujo {
void AgregarArista(int u, int v) { int n; vector<Lista> aristas;
aristas[u].push_back(v); Flujo2D cap, flujo;
aristas[v].push_back(u); Lista padre, dist;
} GrafoFlujo(int N) : dist(N), padre(N),
aristas(N), cap(N, Flujo1D(N)),
void AgregarIzq(int u) { lado[u] = true; } flujo(N, Flujo1D(N)), n(N) {}
void AgregarDer(int u) { lado[u] = false; } void AgregarArista(int u, int v, Flujo c) {
flujo[v][u] += c; // Solo dirigidas!
int CaminoIncremental(int u) { cap[u][v] += c, cap[v][u] += c;
visitado[u] = true; aristas[u].push_back(v);
for (int i = 0; i < aristas[u].size(); ++i) aristas[v].push_back(u);
if (pareja[aristas[u][i]] == -1) }
return pareja[aristas[u][i]] = u;
for(int i = 0; i < aristas[u].size(); ++i){ Edmonds
Karp
int v = aristas[u][i];
if (visitado[pareja[v]]) continue; // Flujo maximo mediante Edmonds-Karp O(VE^2).
if (CaminoIncremental(pareja[v]) != -1) Flujo ActualizarFlujo(int u, Flujo f) {
return pareja[v] = u; int p = padre[u];
} if (p == u) return f;
return -1; f = ActualizarFlujo(p, min(f,
} cap[p][u] - flujo[p][u]));
flujo[p][u] += f;
flujo[u][p] -= f;
return f;
}
24
Flujo AumentarFlujo(int s, int t) { Flujo Dinic(int s, int t) {
fill(padre.begin(), padre.end(), -1); Flujo flujo_maximo = dist[t] = 0;
queue<int> q; q.push(s); padre[s] = s; while (dist[t] < INT_MAX) {
while (!q.empty()) { fill(dist.begin(), dist.end(),INT_MAX);
int u = q.front(); queue<int> q; q.push(s); dist[s] = 0;
q.pop(); if (u == t) break; while (!q.empty()) {
for(int i=0; i<aristas[u].size(); ++i){ int u = q.front(); q.pop();
int v = aristas[u][i]; for(int i = 0;i<aristas[u].size();++i){
if (flujo[u][v] == cap[u][v] || int v = aristas[u][i];
padre[v] != -1) continue; if (flujo[u][v] == cap[u][v] ||
padre[v] = u, q.push(v); dist[v] <= dist[u]+1) continue;
} dist[v] = dist[u]+1, q.push(v);
} }
if (padre[t] == -1) return 0; }
return ActualizarFlujo(t, FINF); if (dist[t] < INT_MAX) flujo_maximo +=
} FlujoBloqueante(s, t, FINF);
Flujo EdmondsKarp(int s, int t) { }
Flujo flujo_maximo = 0, f; return flujo_maximo;
while (f = AumentarFlujo(s, t)) }
flujo_maximo += f; }; //Fin estructura GrafoFLujo
return flujo_maximo;
} Definiciones
Adicionales
// Definiciones adicionales.
Dinic typedef int Costo;
// Flujo maximo mediante Dinic O(V^2E). // Ajustable.
Flujo FlujoBloqueante(int u, int t, Flujo f) { typedef vector<Costo> Costo1D;
if (u == t) return f; Flujo fluido = 0; typedef vector<Costo1D> Costo2D;
for(int i = 0; i < aristas[u].size(); ++i){ typedef pair<Costo, int> CostoNodo;
if (fluido == f) break; typedef pair<Flujo, Costo> FlujoCosto;
int v = aristas[u][i]; const double ERROR = 1e-9;
if (dist[u] + 1 > dist[v]) continue; const Costo CINF = 1 << 30;
Flujo fv = FlujoBloqueante(v, t, // Tolerancia en flotantes.
min(f - fluido, bool Igual(double a, double b) {
cap[u][v] - flujo[u][v])); return fabs(a - b) < ERROR;
flujo[u][v] += fv, fluido += fv; }
flujo[v][u] -= fv;
}
return fluido;
}
25
Emparejamiento
Bipartito
de
costo
MAX/MIN
if (t < 2 * n) {
visitado[t] = true;
// EMPAREJAMIENTO BIPARTITO DE COSTO MAX/MIN if (pareja[t] == -1) {
// Nodos indexados de 0 a n - 1, diferencia emparejado = true;
// entre nodos en el conjunto izquierdo y derecho. for (int p; ; t = p) {
// Es posible que alguna variable se desborde y se pareja[t] = retorno[t];
// cicle, para evitarlo cambien Dato a long long. p = pareja[retorno[t]];
struct BipartitoCosto { pareja[retorno[t]] = t;
Lista pareja, retorno; vector<bool> visitado; if(retorno[t]==i)break;
int n, s; }
Costo1D slack, etiqueta; } else {
Costo2D costo; visitado[t=pareja[t]]=true;
// Emparejamiento de costo maximo S = 1 for (int k = 0; k<n; ++k){
// Emparejamiento de costo minimo S = -1 Costo new_slack =
BipartitoCosto(int N, int S = 1): etiqueta[t] +
costo(N, Costo1D(N, S * -CINF)), s(S), etiqueta[k + n]
slack(2 * N), etiqueta(2 * N), pareja(2*N), - costo[t][k];
retorno(2 * N), visitado(2 * N), n(N) {} if (!Igual(new_slack,
void AgregarArista(int u, int v, Costo c) { slack[k + n])
costo[u][v] = c * s; && new_slack <
} slack[k+ n]){
slack[k + n]=new_slack;
vector<Par> EmparejamientoOptimo() { retorno[k + n] = t;
fill(pareja.begin(), pareja.end(), -1); }
fill(etiqueta.begin(), etiqueta.end(), 0); }
for (int i = 0; i < n; ++i) }
for (int j = 0; j < n; ++j) } else {
etiqueta[i] = max(etiqueta[i], Costo d = CINF;
costo[i][j]); for (int k = n; k < 2 * n; ++k)
for (int i = 0; i < n; ++i) { if (!Igual(slack[k], 0))
for (int j = 0; j < n; ++j) d = min(d, slack[k]);
slack[j + n] = etiqueta[i] + for (int k = 0; k < n; ++k)
etiqueta[j + n] - costo[i][j]; if(visitado[k]) etiqueta[k]-=d;
fill(visitado.begin(), for (int k = n; k < 2 * n; ++k)
visitado.end(),false); if(!visitado[k])slack[k]-=d;
fill(retorno.begin(),retorno.end(), i); else etiqueta[k] += d;
visitado[i] = true; }
bool emparejado = false; }
for (int j = 0; !emparejado; ++j) { }
int t = n; vector<Par> pares;
for (; t < 2 * n; ++t) { for (int i = 0; i < n; ++i)
if (visitado[t]) continue; if (!Igual(costo[i][pareja[i] - n], s*-CINF))
if (Igual(slack[t], 0)) break; pares.push_back(Par(i, pareja[i] - n));
} return pares; // Emparejamiento optimo.
}};// Fin bipartito costo
26
Flujo
Memoria
Optimizada(Dinic)
// Dinic para flujo maximo con memoria optimizada.
// Prefieran esta version solo cuando n > 5,000.
// FLUJO MEMORIA OPTIMIZADA Y Flujo FlujoBloqueante(int u, int t, Flujo f) {
// FLUJO MAXIMO DE COSTO MINIMO if (u == t) return f; Flujo fluido = 0;
// Nodos indexados de 0 a n - 1. for (int i = 0; i < aristas[u].size(); ++i) {
// No utiliza matrices de adyacencia. if (fluido == f) break;
struct GrafoFlujoCosto { AristaFlujo* v = aristas[u][i];
struct AristaFlujo { if (dist[u] + 1 == dist[v->dst]) {
int dst; AristaFlujo* residual; Flujo fv = FlujoBloqueante(v->dst, t,
Flujo cap, flujo; Costo peso, npeso; min(f - fluido, v->cap - v->flujo));
AristaFlujo(int d, Flujo f, Flujo c) v->AumentarFlujo(fv), fluido += fv;
: dst(d), flujo(f), cap(c) {} }
Costo AumentarFlujo(Flujo f) { }
residual->flujo -= f; return fluido;
this->flujo += f; }
return peso * f; Flujo Dinic(int s, int t) {
} Flujo flujo_maximo = dist[t] = 0;
}; while (dist[t] < INT_MAX) {
int n; vector<Par> prv; Lista dist; fill(dist.begin(), dist.end(), INT_MAX);
vector< vector<AristaFlujo*> > aristas; queue<int> q; q.push(s); dist[s] = 0;
GrafoFlujoCosto(int N) : n(N), aristas(N), while (!q.empty()) {
prv(N), dist(N) {} int u = q.front(); q.pop();
~GrafoFlujoCosto() { for (int i = 0; i<n; ++i) for (int i=0; i<aristas[u].size();++i){
for (int j = 0; j < aristas[i].size(); ++j) AristaFlujo* v = aristas[u][i];
delete aristas[i][j]; if (dist[v->dst]< INT_MAX)continue;
// NO OMITIR if (v->flujo == v->cap) continue;
} dist[v->dst] = dist[u] + 1;
// Para aristas bidireccionales agreguen dos q.push(v->dst);
// aristas dirigidas. Si las aristas no son }
ponderadas dejen el ultimo parametro con el valor }
por defecto. if (dist[t] < INT_MAX)
flujo_maximo+=FlujoBloqueante(s,t,FINF);
void AgregarArista( }
int u, int v, Flujo c, Costo p = 0) { return flujo_maximo;
AristaFlujo* uv = new AristaFlujo(v, 0, c); }
AristaFlujo* vu = new AristaFlujo(u, c, c);
uv->residual = vu, vu->residual = uv;
uv->peso = uv->npeso = p;
vu->peso = vu->npeso = -p;
aristas[u].push_back(uv);
aristas[v].push_back(vu);
}
27
Max-‐Flow
Min-‐Cost
if(Igual(dist[t], CINF))return FlujoCosto(0,0);
RecalcularCosto(dist);
//Flujo de costo minimo en O(VElogV * flow). Si return ActualizarFlujo(t, f);
dejan el valor por defecto del parametro k saca el }
flujo maximo. FlujoCosto FlujoCostoMin(int s,int t, Flujok=FINF){
void RecalcularCosto(const Costo1D& pi) { Costo1D dist(n, CINF); dist[s] = 0;
for (int u = 0; u < n; ++u) { for (int i = 0; i < n; ++i) {
for(int i = 0; i < aristas[u].size(); ++i){ for (int u = 0; u < n; ++u) {
AristaFlujo* v = aristas[u][i]; if (Igual(dist[u], CINF)) continue;
v->npeso = v->npeso + pi[u]-pi[v->dst]; for(int j=0; j<aristas[u].size(); ++j){
} AristaFlujo* v = aristas[u][j];
} if (v->flujo < v->cap)
} dist[v->dst]= min(dist[v->dst],
FlujoCosto ActualizarFlujo(int u, Flujo f) { dist[u] + v->npeso);
int p = prv[u].first, i = prv[u].second; }
if (p == -1) return FlujoCosto(f, 0); }
AristaFlujo* pu = aristas[p][i]; }
FlujoCosto res = ActualizarFlujo(p, RecalcularCosto(dist);
min(f, pu->cap - pu->flujo)); FlujoCosto flujo_costo(0, 0);
res.second += pu->AumentarFlujo(res.first); while (flujo_costo.first < k) {
return res; FlujoCosto fc = AumentarFlujo(s, t, k-
} flujo_costo.first);
FlujoCosto AumentarFlujo(int s, int t, Flujo f) { flujo_costo.second += fc.second;
Costo1D dist(n, CINF); flujo_costo.first += fc.first;
fill(prv.begin(), prv.end(), Par(-1, -1)); if (!fc.first) break;
priority_queue<CostoNodo, vector<CostoNodo>, }
greater<CostoNodo> > pq; return flujo_costo;
pq.push(FlujoCosto(0, s)); dist[s] = 0; }
while (!pq.empty()) { }; //Fin estructura GrafoFlujoCosto
int u = pq.top().second;
Costo p = pq.top().first; pq.pop();
if (!Igual(dist[u], p)) continue;
for (int i= 0; i < aristas[u].size(); ++i){
AristaFlujo* v = aristas[u][i];
if (v->flujo == v->cap) continue;
Costo ndist = dist[u] + v->npeso;
if (!Igual(ndist, dist[v->dst]) &&
ndist < dist[v->dst]) {
dist[v->dst] = dist[u] + v->npeso;
pq.push(CostoNodo(ndist, v->dst));
prv[v->dst].second = i;
prv[v->dst].first = u;
}
}
}
28
Estructuras
de
Datos
SegmentTree
Dinámico
const int INF = 1 << 30;
Sparse
Table
// Segment Tree version dinamica. Para generar el
#define ll long long // arbol completo deben llamar a la funcion
#define MAXN 100005 Construir. CUIDADO: Para usarlo deben especificar
#define LOGN 20 el tipo de dato a utilizar;
using namespace std; template<class T> struct SegTree {
ll sparse [MAXN][LOGN], A[MAXN]; T dato; int i, d;
int logs[MAXN]; SegTree* izq, *der;
SegTree(int I, int D): izq(NULL), der(NULL),
ll gcd(ll a, ll b){ i(I), d(D), dato() {}
if(b==0) ~SegTree() {
return a; if (izq) delete izq;
ll GCD=gcd(b, a%b); if (der) delete der;
return GCD; }
} T Construir() {
void pre(int N){ if (i == d) return dato = T();
for(int i = 2; i <= N; i++) int m = (i + d) >> 1;
logs[i] = logs[i/2] + 1; izq = new SegTree(i, m);
for(int i = 0; i < N; i++) der = new SegTree(m + 1, d);
sparse[i][0] = A[i]; return dato=izq->Construir()+der->Construir();
for(int i = 0; i < logs[N]; i++) }
for(int j = 0; j < N; j++) T Actualizar(int a, T v) {
sparse[j][i+1] = gcd(sparse[j][i], if (a < i || d < a) return dato;
sparse[min(j + (1<<i), N-1)][i]); if (a == i && d == a) return dato = v;
} if (!izq) {
int m = (i + d) >> 1;
ll query (int a, int b){ izq = new SegTree(i, m);
if(a == b) return sparse[a][0]; der = new SegTree(m + 1, d);
int L = logs[b-a+1]; }
return gcd(sparse[a][L], return dato = izq->Actualizar(a, v) +
sparse[b-(1 << L)+1][L]); der->Actualizar(a, v);
} }
T Query(int a, int b) {
if (b < i || d < a) return T();
if (a <= i && d <= b) return dato;
return izq? izq->Query(a, b) +
der->Query(a, b): T();
}
};
29
// A continuación se ejemplifica como sobrecargar data Query(int a, int b, int n, int L, int R) {
// el operador + dentro de una estructura para if (L > b || R < a) return data(MINF, MINF);
poder reutilizar el codigo del Segment Tree if (L >= a && R <= b) return ST[n];
facilmente. El ejemplo sobrecarga el + por la int mid = (L + R) >> 1;
funcion de maximo. Es MUY IMPORTANTE tener un return Combina(Query(a, b, n << 1, L, mid),
constructor por defecto. Query(a, b, (n << 1) + 1, mid + 1, R));
struct MaxInt { }
int d; MaxInt(int D) : d(D) {} int main() {
MaxInt() : d(-INF) {} // IMPORTANTE! int N, Q, a, b;
MaxInt operator+(const MaxInt& o) { char opc;
return MaxInt(max(d, o.d)); data ans;
} cin >> N;
}; for (int i = 1; i <= N; i++) {
cin >> a;
Segment
Tree
(Single
U,
Range
Q)
//Update o cambio de valor en el Arreglo
const int SIZE = (1 << 22) + 5; posicion i
const int MINF = -(1e9); Update(i, i , a, 1, 1, N);
typedef pair<int, int> data; }
//ST indexado desde uno cin >> Q;
data ST[SIZE]; for (int i = 0; i < Q; ++i) {
cin >> opc >> a >> b;
data Combina(data A, data B) { if (opc == ‘Q’) {
if (B.first > A.first) { //Query del rango a - b en el arreglo
swap(A.first, B.first); ans = Query(a, b, 1, 1, N);
swap(B.first, A.second); if (a == b) cout << ans.first<<’\n’;
if (B.second > A.second) else cout<<ans.first+ans.second<<‘\n’;
swap(A.second, B.second); }
} else if (B.first > A.second) else Update(a, a, b, 1, 1, N);
swap(B.first, A.second); }
return A; }
}
Segment
Tree
Lazy
(Single
U,
Range
Q)
void Update(int a,int b,int v,int n, int L, int R){ const int MAXN = 500009;
if (L > b || R < a) return; typedef long long lli;
if (L >= a && R <= b) { lli ST[MAXN], Lazy[MAXN], arr[MAXN], N;
ST[n] = data(v, MINF); return; void Build(int n = 1, int L = 1, int R = N) {
} if (L == R) {
int mid = (L + R) >> 1; ST[n] = arr[L];
Update(a, b, v, n << 1, L, mid); return;
Update(a, b, v, (n << 1) + 1, mid + 1, R); }
ST[n] = Combina (ST[(n << 1)], ST[(n << 1)+1]); int ls = (n << 1), rs = ls + 1, m =(L + R) >>1;
} Build(ls, L, m); Build(rs, m + 1, R);
ST[n] = max(ST[ls], ST[rs]);
}
30
void Update(int r, lli v, int l = 1, int n = 1, int int main() {
L = 1, int R = N) { cin >> N;
if ((L > r) || (R < l)) return; for (int i = 1; i <= N; ++i) cin >> arr[i];
int ls = (n << 1), rs = ls + 1, m = (L + R)>>1; Build();
if (Lazy[n] && (L != R)) { int Q; cin >> Q;
ST[ls] = Lazy[n]; for (int i = 0; i < Q; ++i) {
ST[rs] = Lazy[n]; int I, J;
Lazy[ls] = Lazy[n]; cin >> I >> J;
Lazy[rs] = Lazy[n]; cout << Query(1, I) << '\n';
Lazy[n] = 0;
} Update(I, (Query(1, I) + J));
if ((L >= l) && (R <= r)) { }
ST[n] = v; return 0;
Lazy[n] = v; }
return;
}
Update(r, v, l, ls, L, m); Estructura
Fenwick
Tree
Update(r, v, l, rs, m + 1, R);
// Fenwick Tree. Indices de 1 a n.
ST[n] = max(ST[ls], ST[rs]);
struct FenTree {
}
vector<int> tree;
lli Query(int l, int r, int n = 1, int L = 1, int R
FenTree(int n) : tree(n + 1) {}
= N) {
if ((L > r) || (R < l)) return -1LL;
void Actualizar(int i, int v) {
int ls = (n << 1), rs = ls + 1, m = (L + R)>>1;
while (i < tree.size()) {
if (Lazy[n] && (L != R)) {
tree[i] += v;
ST[ls] = Lazy[n];
i += i & -i;
ST[rs] = Lazy[n];
}
Lazy[ls] = Lazy[n];
}
Lazy[rs] = Lazy[n];
int Query(int i) {
Lazy[n] = 0;
int sum = 0;
}
while (i > 0) {
if ((L >= l) && (R <= r)) return ST[n];
sum += tree[i]; i -= i & -i;
return max(Query(l, r, ls, L, m),
}
Query(l, r, rs, m + 1, R));
return sum;
}
}
int Rango(int i, int j) {
return Query(j) - Query(i - 1);
}
};
31
Pila
Incremental
long long H[1000009], W[1000009];
int main(){
int N; cin >> N;
for (int i = 0; i < N; ++i)
cin >> H[i], W[i] = 1;
H[N] = -1; W[N] = 1;
stack<int> Q;
long long res = -1, cnt;
int qt;
for (int i = 0; i <= N; ++i) {
if (Q.empty()) Q.push(i);
else {
if (H[i] >= H[Q.top()]) Q.push(i);
else {
qt = Q.top(); cnt = 0;
while (H[qt] > H[i]) {
cnt += W[qt];
res = max(res, H[qt] * cnt);
Q.pop();
if (Q.empty()) break;
qt = Q.top();
}
W[i] += cnt;
Q.push(i);
}
}
}
cout << res << “\n”;
}
32
Strings
vector<int> LCP(const string& str,
const vector<int>& sa) {
vector<int> lcp(str.size());
Suffix
Array
vector<int> plcp(str.size());
void BucketSort(vector<int>& sa, vector<int> phi(str.size(), -1);
const vector<int>&rank, int ranks){ for(int i = 1; i < str.size(); ++i)
vector<int> bucket(ranks, 0); phi[sa[i]] = sa[i - 1];
vector<int> tmp_sa(sa.size()); int len = 0;
for (int i = 0; i < sa.size(); ++i) for(int i = 0; i < str.size(); ++i) {
++bucket[rank[sa[i]]]; if (phi[i] == -1) continue;
for (int i = 0, sum = 0; i < ranks; ++i) for (; str[phi[i] + len] ==
swap(bucket[i], sum), sum += bucket[i]; str[i + len]; ++len) {}
for (int i = 0; i < sa.size(); ++i) plcp[i] = len; len = max(len-1, 0);
tmp_sa[bucket[rank[sa[i]]]++] = sa[i]; }
swap(sa, tmp_sa); for (int i = 0; i < str.size(); ++i)
} lcp[i] = plcp[sa[i]];
// Recuerden poner '$' al final de la cadena. return lcp;
vector<int> SuffixArray(const string& str) { }
int ranks = 255; vector<int> sa(str.size()); Ejemplo
vector<int> nrank(str.size());
vector<int> rank(str.size(), 0); int main() {
vector<int> tmp_rank(str.size()); string cadena; cin >> cadena;
for (int i = 0; i < str.size(); ++i) cadena += ‘$’;
nrank[i] = str[i], sa[i] = i; vector <int> sufix = SuffixArray(cadena);
for (int p = 0; true; ++p) { vector<int> lcp = LCP(cadena , sufix);
BucketSort(sa, nrank, ranks + 1); for (int i = 0; i < cadena.size(); i++){
BucketSort(sa, rank, ranks + 1); cout << sufix[i] << “\t” <<
tmp_rank[0] = ranks = 0; cadena.substr(sufix[i])<< “\t” <<
for (int i = 1; i < str.size(); ++i) lcp[i] << endl;
if (rank[sa[i]] != rank[sa[i - 1]] || }
nrank[sa[i]] != nrank[sa[i - 1]]) return 0;
tmp_rank[i] = ++ranks; }
else tmp_rank[i] = ranks;
if (ranks + 1 == str.size()) break; KMP
for (int i = 1; i <= 1 << p; ++i) int F[1000009];
nrank[str.size() - i] = 0; //Pattern and Text
for (int i = 0; i < str.size(); ++i) { string P, T;
int prv = sa[i] - (1 << p); void CF() {
if (prv >= 0) nrank[prv]=tmp_rank[i]; F[0] = -1;
rank[sa[i]] = tmp_rank[i]; for (int i = 0, j = -1; P[i]; ) {
} while (~j && P[i] != P[j]) j = F[j];
} F[++i] = ++j;
return sa; }
} }
33
void KMPSearch() { vector<ull> MhasH(string s) {
int i = 9, j = 0; vector<ull> hasH(s.size() + 1, 0);
while (i < T.size()) { for (int i = 1; i <= s.size(); ++i)
while (j >= 0 && T[i] != P[j]) j = F[j]; hasH[i] = (Multiplicar(hasH[i - 1], B, MOD)
i++; j++; + F(s[i - 1])) % MOD;
if (j == P.size()) { return hasH;
printf(“P is found at index %d in T\n”, i–j); }
j = F[j];
} Minimum
Rotating
String
&
BinSearch
(
returns
first
}
} inequality
index
)
cin >> s; int N = s.size();
Hashing
ss = s + s;
#define ull unsigned long long vector<ull> THash = Mhash(ss);
const int MAXC = 20000005; int i = 0, k = 1, ans;
const ull MOD = 100000000000000003LL; for (; k < N; ++k) {
const ull MOD2 = 100000000000000013LL; //cout << Subs(THash, i + 1, i + N) << “ -
“ << Subs(THash, k + 1, k + N) << ‘\n‘;
ull HB[MAXC], B = 71; if (Subs(THash, i + 1, i + N) ==
ull Multiplicar(ull a, ull b, ull m) { Subs(THash, k + 1, k + N)) continue;
ull res = 0, p = a; int in = 1, fin = N + 1, mid;
for (; b; b >>= 1) { while (in < fin) {
if (b & 1) res = (res + p) % m; mid = (in + fin) / 2;
p = (p + p) % m; if (Subs(THash, i + 1, i + mid) !=
} Subs(THash, k + 1, k + mid))
return res; fin = mid;
} else in = mid + 1;
}
ull Subs(const vector<ull>& hasH, int a, int b) { //cout << “Comparamos: “ << ss.substr(i, N)
return (hasH[b] - Multiplicar(hasH[a - 1] << “ Con: “ << ss.substr(k, N) << ‘\n’;
, HB[b - a + 1], MOD)) % MOD; //cout << “Salieron diferentes del
} caracter: “ << fin << ‘\n’;
if (ss[i + fin - 1] > ss[k + fin - 1]) {
ull F(char c) { //cout<<ss[i + fin - 1] <<“-“<< ss[k +
return c – ‘a‘ + 1; fin - 1] << “ “ << k << ‘\n’;
} ans = k; i = k;
}
void CB() { }
HB[0] = 1; HB[1] = B; cout << ans << ‘\n’;
for (int i = 2; i < MAXC; ++i)
HB[i] = Multiplicar(HB[i - 1], B, MOD);
}
34
Trie
//Si hay repetidos dice cuantas veces aparece la
palabra. Si no hay repetido, dice si está o no está
struct nodoTrie{ esa palabra
int w; int BuscaPalabra(string &cadena){
//El numero de palabras que terminan en este nodo int posS = 0;
int p; int posT = 0, sigN;
//El número de palabras que tienen el camina de la while(posS < cadena.size()){
raíz a este nodo como prefijo sigN = nodos[posT].h[cadena[posS]-'a'];
int h[26]; if(sigN == -1) return 0;
//Los hijos del nodo para cada letra posT = sigN;
void inicializa(){ posS++;
w = p = 0; }
for(int i = 0 ; i < 26 ; i++) return nodos[posT].w;
h[i] = -1;//-1 para hijos aún no creados }
} //Regresa la cantidad de palabras que tienen a
}; $cadena$ como prefijo
struct Trie{ int Prefijo(string &cadena){
int inc; int posS = 0; int posT = 0, sigN;
vector<nodoTrie>nodos; while(posS < cadena.size()){
//Inicializa la cosa esta. sigN = nodos[posT].h[cadena[posS]-'a'];
//rep = 1 si hay repetidos. 0 si no hay. if(sigN == -1) return 0;
Trie(int rep){ inc = rep; posT = sigN;
nodos = vector<nodoTrie>(1); posS++;
nodos[0].inicializa(); }
} return nodos[posT].p;
}
//Agrega una palabra al trie. };
void AgregaPalabra(string &cadena){
int posS = 0, posT = 0 , sigN ;
while(posS < cadena.size()){
sigN = nodos[posT].h[cadena[posS]-'a'];
if(sigN != -1) posT = sigN;
else {
sigN = nodos.size();
nodos.resize(sigN+1);
nodos[sigN].inicializa();
nodos[posT].h[cadena[posS]-'a']= sigN;
posT = sigN;
}
posS++; nodos[posT].p++;
}
if(!nodos[posT].w) nodos[posT].w = 1;
else nodos[posT].w += inc;
}
35
Matemagias
Factores
del
Factorial
typedef long long Long;
// Factores primos de n factorial (n!). El vector
de primos debe estar ordenado.
Factores
Primos
vector<Factor> FactoresFactorial(int n,
// Factores primos de un numero a. const vector<int>& primos) {
typedef pair<int, int> Factor; vector<Factor> factores;
vector<Factor> FactoresPrimos(int a) { for (int i = 0; i < primos.size(); ++i) {
int conteo = 0; if (n < primos[i]) break;
vector<Factor> factores; int p = primos[i]; int reps = n / p;
while (!(a & 1)) ++conteo, a >>= 1; while (primos[i] <= n / p)
if (conteo) factores.push_back(Factor(2, p *= primos[i], reps += n / p;
conteo)), conteo = 0; factores.push_back(Factor(primos[i],reps));
int raiz = sqrt(a); }
for (int i = 3; i <= raiz; i += 2) { return factores;
while (!(a % i)) ++conteo, a /= i; }
if (conteo) factores.push_back(Factor(i,
conteo)), conteo = 0; Exponenciación
Binaria
}
if (a > 1) factores.push_back(Factor(a, 1)); // Exponenciacion binaria a^n mod m.
return factores; Long Exponenciar(Long a, Long n, Long m) {
} Long resultado = 1;
for (; n; n >>= 1) {
if (n & 1) resultado = (resultado * a) % m;
Criba
a = (a * a) % m;
// Criba de Eratostenes de 1 a n. }
vector<int> Criba(int n) { return resultado;
int raiz = sqrt(n); }
vector<int> criba(n + 1);
for (int i = 4; i <= n; i += 2) Multiplicación
Binaria
criba[i] = 2;
for (int i = 3; i <= raiz; i += 2) // Multiplicacion binaria a*b mod m.
if (!criba[i]) Long Multiplicar(Long a, Long b, Long m) {
for (int j = i * i; j <= n; j += i) Long resultado = 0;
if (!criba[j]) criba[j] = i; for (; b; b >>= 1) {
return criba; if (b & 1) resultado = (resultado + a) % m;
} a = (a + a) % m;
}
return resultado;
}
36
Euclides
Extendido
bool operator<(const Fraccion& cmp) {
Long gcd = __gcd(den, cmp.den);
// Algoritmo de Euclides extendido entre a y b. return num * (cmp.den / gcd) <
Además de devolver el gcd(a, b), resuelve la cmp.num * (den / gcd);
identidad de Bezout con el par (x, y). }
Si el parámetro mod no es especificado, se resuelve bool operator==(const Fraccion& cmp) {
con aritmetica normal; si mod se especifica, la Long gcd = __gcd(den, cmp.den);
identidad se resuelve modulo mod. return num * (cmp.den / gcd) ==
Long Euclides(Long a, Long b, Long& x, cmp.num * (den / gcd);
Long& y, Long mod = 0) { }
if (!b) { x = 1, y = 0; return a; } }; //Fin estructura Fracción
Long gcd = Euclides(b, a % b, x, y, mod);
x = !mod? x - y * (a / b):
(mod + x - (y * (a / b)) % mod) % mod; Eliminación
Gaussiana
swap(x, y); // Eliminacion Gaussiana de matrices.
return gcd; Definiciones iniciales para Gauss-Jordan.
} typedef vector<double> Vector;
typedef vector<Vector> Matriz;
Estructura
Fracción
// Para eliminacion con fracciones.
Fraccion fabs(const Fraccion& f) {
// Tipo de dato para operar fracciones. return Fraccion(abs(f.num), f.den);
struct Fraccion { }
Long num, den; bool EsCero(const Fraccion& f) {
Fraccion() : num(0), den(1) {} return f.num == 0;
Fraccion(Long n, Long d) { }
if (d < 0) n = -n, d = -d; // Para eliminacion con flotantes.
Long gcd = __gcd(abs(n), abs(d)); const double ERROR = 1e-9;
num = n / gcd, den = d / gcd; bool EsCero(double a) {
} return fabs(a) < ERROR;
Fraccion operator-() const { }
return Fraccion(-num, den);
}
Fraccion operator+(const Fraccion& f) { Phi
de
Euler
Long gcd = __gcd(den, f.den); long long EulerPhi(long long n){
return Fraccion(num * (f.den / gcd)+ long long ans = n, i;
f.num *(den / gcd), den * (f.den / gcd)); for (i = 2; i * i <= n; ++i) {
} if (n % i == 0) {
Fraccion operator-(const Fraccion& f) { while (n % i == 0) n /= i;
return *this + -f; // a - b = a + (-b) ans -= ans / i;
} }
Fraccion operator*(const Fraccion& f) { }
return Fraccion(num * f.num, den * f.den); if (n > 1) ans -= ans / n
} return ans;
Fraccion operator/(const Fraccion& f) { }
return Fraccion(num * f.den, den * f.num);
}
37
// En caso de no permitir el pivoteo (eg. cuando // Fast
And
Fourier
requieran sacar una matriz inversa) simplemente //
comenten o borren la seccion <comment>. // Transformada rapida de Fourier. Se tiene que
void EliminacionGaussiana(Matriz& m) { garantizar que el numero de elementos en el vector
for (int i = 0; i < m.size(); ++i) { sea una potencia de 2.
// <comment> const double M_2PI = 2 * M_PI;
int fila_mayor = i; vector<Complejo> FastAndFourier(
for (int j = i + 1; j < m.size(); ++j) const vector<Complejo> &a, int k = 1) {
if (fabs(m[fila_mayor][i]) < fabs(m[j][i])) int n = a.size();
fila_mayor = j; if (n == 1) return a;
swap(m[i], m[fila_mayor]); vector<Complejo> par, impar;
// </comment> for (int i = 0; i < n; ++i)
if (EsCero(m[i][i])) continue; if (i & 1) par.push_back(a[i]);
for (int j = m[i].size() - 1; j >= i; --j) else impar.push_back(a[i]);
m[i][j] = m[i][j] / m[i][i]; impar = FastAndFourier(impar, k);
for (int j = 0; j < m.size(); ++j) { par = FastAndFourier(par, k);
if (i == j || EsCero(m[j][i])) continue; vector<Complejo> fourier(n);
for (int k = m[j].size() - 1; k >= i; --k) Complejo w(1, 0),
m[j][k] = m[j][k] - m[i][k] * m[j][i]; wn(cos(-k * M_2PI/n), sin(-k * M_2PI/n));
} for (int i = 0; i < n/2; w = w * wn, ++i) {
} fourier[i + n/2] = impar[i] - w * par[i];
} fourier[i] = impar[i] + w * par[i];
}
return fourier;
Estructura
Complejo
}
// Tipo de dato para operar numeros complejos.
struct Complejo { Fast
And
Fourier
Invertida
double real, imag;
Complejo() : real(), imag() {} // Transformada inversa de Fourier. Se tiene que
Complejo(double r, double i):real(r),imag(i) {} garantizar que el numero de elementos en el vector
Complejo operator+(const Complejo& c) { sea una potencia de 2.
return Complejo(real+c.real, imag+c.imag); vector<Complejo> InvFastAndFourier(
} const vector<Complejo>& a) {
Complejo operator-(const Complejo& c) { vector<Complejo> ifft = FastAndFourier(a, -1);
return Complejo(real-c.real, imag-c.imag); for (int i = 0; i < ifft.size(); ++i)
} ifft[i].real /= ifft.size(),
Complejo operator*(const Complejo& c) { ifft[i].imag /= ifft.size();
return Complejo(real*c.real - imag*c.imag, return ifft; }
real * c.imag + imag * c.real);
}
};
38
Convolución
Discreta
// Convolucion discreta de dos vectores usando Josephus
Problem
transformada rapida de Fourier O(n log n). //Se avanzan k pasos de forma circular durante n -
Multiplica eficientemente dos polinomios. 1 rondas hasta que solo uno quede vivo
Vector ConvolucionDiscreta( const Vector& a, g(n,k) = (g(n - 1, k) + k) mod n
const Vector& b) { g(1, k) = 0
int n = a.size() + b.size() - 1;
int p = 1; while (p < n) p <<= 1; Ley
de
Seno
vector<Complejo> A(p), B(p), C(p);
𝑎 𝑏 𝑐
for (int i = 0; i < a.size(); ++i) 𝐷= = =
A[i] = Complejo(a[i], 0); sin (𝐴) sin (𝐵) sin (𝐶)
for (int i = 0; i < b.size(); ++i) 1 1 1
Á𝑟𝑒𝑎 = 𝑏𝑐 sin A = 𝑐𝑎 sin 𝐵 = 𝑎𝑏(sin (𝐶))
B[i] = Complejo(b[i], 0); 2 2 2
A = FastAndFourier(A);
B = FastAndFourier(B); Ley
de
Coseno
for (int i = 0; i < p; ++i) 𝑐 ! = 𝑎 ! + 𝑏 ! − 2𝑎𝑏 ∗ 𝑐𝑜𝑠(𝐶)
C[i] = A[i] * B[i];
𝑎 ! = 𝑏 ! + 𝑐 ! − 2𝑏𝑐 ∗ 𝑐𝑜𝑠 𝐴
C = InvFastAndFourier(C);
𝑏 ! = 𝑎 ! + 𝑐 ! − 2𝑎𝑐 ∗ cos 𝐵
Vector convolucion(n);
for (int i = 0; i < n; ++i)
convolucion[i] = C[i].real; Fórmula
de
Herón
return convolucion; 𝐴𝑟𝑒𝑎 = 𝑝 ∗ 𝑝 − 𝑎 ∗ 𝑝 − 𝑏 ∗ (𝑝 − 𝑐)
} Donde
𝑎+𝑏+𝑐
Tolerancia
a
flotantes
𝑝 =
2
bool Igual(double a, double b) {
return fabs(a - b) < ERROR;
}
Multiplicar
Matrices
//Multiplica una matriz de tamano n*m por una
matriz de m*l, el resultado es una matriz de n*l
Matriz MultiplicarMatriz(const Matriz &a,
const Matriz &b){ Inverso
modular
Matriz producto(a.size(),
vector<double>(b[0].size(), 0.0000)); El inverso multiplicativo de un número 𝑎 módulo 𝑚:
for(int i = 0; i < a.size(); i++) 𝑥 en 𝑎𝑥 + 𝑚𝑦 = 1 o 𝑎 !(!) – ! 𝑚𝑜𝑑𝑢𝑙𝑜 𝑚
for(int j = 0; j < b[0].size(); j++)
for(int k = 0; k < b.size(); k++) Primos
Grandes
producto[i][j] += a[i][k]*b[k][j];
10^9 + 9, 10^9 + 21, 10^9 + 33, 999999937,
return producto;
} 999999929.
39
Triángulo
de
pascal
• Mediatriz:
La
mediatriz
de
un
lado
de
un
triángulo
se
define
const int mod = 1e9 + 7; como
la
recta
perpendicular
a
dicho
lado
que
pasa
por
su
C[0][0] = 1LL; punto
medio.
for (int i = 1; i < MAXN; ++i) { • Los
puntos
de
la
mediatriz
de
un
lado
de
un
triángulo
C[i][0] = 1LL; equidistan
de
los
vértices
que
definen
dicho
lado.
for (int j = 1; j <= i; j++)
C[i][j]=(C[i - 1][j - 1] + C[i -1][j])% mod; • Altura:
La
altura
de
un
triángulo,
respecto
de
uno
de
sus
} lados,
se
define
como
la
recta
perpendicular
a
dicho
lado
que
pasa
por
el
vértice
opuesto.
Combinatoria
• En
un
triángulo
isósceles,
la
altura
correspondiente
al
lado
Long Combinatoria(Long n, Long r){ desigual
divide
el
triángulo
en
dos
triángulos
iguales.
if (r > n) return 0; • Mediana:
La
mediana
de
un
triángulo,
correspondiente
a
uno
if( r == 0 ) return 1; de
sus
vértices,
se
define
como
la
recta
que
une
dicho
vértice
Long v = n--, inverso, x, y; del
triángulo
con
el
punto
medio
del
lado
opuesto.
for (Long i = 2; i < r + 1; ++i, --n){
Euclides( i, modulo, x, y, modulo ); • Las
tres
medianas
de
un
triángulo
son
interiores
al
mismo,
v = (((v * n) % modulo) * x ) % modulo; independientemente
del
tipo
de
triángulo
que
sea.
} • Cada
mediana
de
un
triángulo
divide
a
éste
en
dos
triángulos
return v; de
igual
área.
} • Bisectriz:
La
bisectriz
de
un
triángulo,
correspondiente
a
uno
de
sus
vértices,
se
define
como
la
recta
que,
pasando
por
Radio
incentro
dicho
vértice,
divide
al
ángulo
correspondiente
en
dos
partes
(𝑠 − 𝑎)(𝑠 − 𝑏)(𝑠 − 𝑐) iguales.
𝑟 = • Los
puntos
de
la
bisectriz
equidistan
de
los
lados
del
ángulo.
𝑠
• El
baricentro
de
un
triángulo,
es
un
punto
interior
al
mismo,
Radio
circuncentro
que
dista
el
doble
de
cada
vértice
que
del
punto
medio
de
su
lado
opuesto.
𝑎∗𝑏∗𝑐
𝑟= • El
Ortocentro,
Baricentro
y
Circuncentro
están
siempre
4 ∗ 𝐴𝑟𝑒𝑎 alineados.
(Recta
de
Euler)
• El
baricentro
está
entre
el
ortocentro
y
circuncentro.
Incentro
• La
distancia
del
baricentro
al
circuncentro
es
la
mitad
que
la
𝑎 𝑥! + 𝑏𝑥! + 𝑐𝑥! 𝑎𝑦! + 𝑏𝑦! + 𝑏𝑦!
𝑷 𝒙, 𝒚 = ( , ) distancia
del
baricentro
al
ortocentro.
M
𝑎+𝑏+𝑐 𝑎+𝑏+𝑐
• Incentro:
Punto
en
el
que
se
cortan
las
3
bisectrices,
es
el
Definiciones
centro
de
la
circunferencia
inscrita.
Equidista
de
sus
3
lados,
siendo
tangente
a
ellos.
Triángulos
• Circuncentro:
Es
el
punto
de
corte
de
las
3
mediatrices.
• La
recta
que
une
los
puntos
medios
de
dos
lados
de
un
triángulo
es
paralela
al
tercer
lado
e
igual
a
su
mitad,
y
se
llama
paralela
media
correspondiente
al
tercer
lado.
40
Extra
Precision
cout
Fórmula
de
los
caballos
double res = algo;
typedef long long int Long; cout.setf(ios::fixed,ios::floatfield);
struct punto{ cout.precision(3); cout << res << ‘\n’;
Long x,y;
punto(){ x = 0, y = 0;}
};
Big
Integer
/
Java
int precalc[5][5] = {{0}, import java.util.Scanner;
{3,2}, import java.math.BigInteger;
{2,1,4}, class Main {
{3,2,3,2}, public static void main(String[] args) {
{2,3,2,5,4}}; Scanner sc = new Scanner(System.in);
Long calcula(punto A,punto B){ int caseNo = 1;
Long x,y,tam; while (true) {
Long a,st,nd; int N = sc.nextInt(), F = sc.nextInt();
x = abs(A.x-B.x); if (N == 0 && F == 0) break;
y = abs(A.y-B.y); BigInteger sum = BigInteger.ZERO
if(x > y) swap(x,y); for (int i = 0; i < N; i++) {
if(y < 5) return precalc[y][x]; BigInteger V = sc.nextBigInteger();
else { sum = sum.add(V);
if(y & 1) tam = y/2 + 4; }
else tam = y/2 + 2; System.out.println(sum.divide(
if(x >= tam){ BigInteger.valueOf(F)));
a = y-x; }
x += a/2; }
y -= a/2; }
if( a & 1 ) return ((x+1)/3)*2 +1;
return (((x-1)/3)+1)*2; Constructor
} else { BigInteger(String val) // Translates the decimal
a = y/2; String representation of a BigInteger into a
if(y&1){ BigInteger.
if(a&1) st = a+2;nd = a+1;
else st = a+1;nd = a+2;
} else { Constantes
if(a&1) st = a+1;nd = a; Static BigInteger ONE //The BigInteger constant
else st = a; nd = a+1; one.
} Static BigInteger TEN //The BigInteger constant
if(x&1) return nd; ten.
return st; Static BigInteger ZERO //The BigInteger constant
} zero.
}
}
41
Métodos
• BigInteger nextProbablePrime() // Returns the
first integer greater than this BigInteger that
• BigInteger abs() //Returns a BigInteger whose
is probably prime.
value is absolute value of this BigInteger.
• BigInteger pow( int exponent ) //Returns a
• BigInteger add(BigInteger val) //Returns
BigInteger whose value is( thisexponent ).
BigInteger whose value is ( this + val ).
• BigInteger remainder( BigInteger val ) //
• BigInteger compareTo(BigInteger val ) //Compares
Returns a BigInteger whose value is (this %
this BigInteger with the specified BigInteger.
val).
• BigInteger divide(BigInteger val ) //Returns a
• BigInteger substract( BigInteger val ) //Returns
BigInteger whose value is ( this / val ).
a BigInteger whose value is (this - val).
• BigInteger[] divideAndRemainder(BigInteger val )
• String toString() //Returns the decimal String
//Returns an array of two BigIntegers containing
representation of this BigInteger.
( this / val ) followed by (this % val).
• Static BigInteger valueOf( long val ) // Returns
• double doubleValue() //Converts this BigInteger
a BigInteger whose value is equal to that of the
to a double.
specified long.
• float floatValue() //Converts this BigInteger to
a float
Primos
hasta
el
1000
• BigInteger gcd(BigInteger val ) //Returns a
BigInteger whose value is the gratest common
divisor of abs(this) and abs(val).
• int intValue() //Converts this BigInteger to an
int.
• long longValue() //Converts this BigInteger to a
long.
• BigInteger max(BigInteger val ) //Returns the
maximum of this BigInteger and val.
• BigInteger min(BigInteger val ) //Returns the
minimum of this BigInteger and val.
• BigInteger mod(BigInteger m ) // Returns a
BigInteger whose value is (this mod m).
• BigInteger modInverse (BigInteger m) //Returns a Códigos
Rivas
BigInteger whose value is (this-1 mod m).
• BigInteger modPow(BigInteger exponent,
BigInteger m) //Returns a BigInteger whose value Robbing
Gringotts
is ( thisexponent mod m). //Meet in the middle
• BigInteger multiply (BigInteger val ) //Returns #include <bits/stdc++.h>
a BigInteger whose value is ( this * val ). using namespace std;
const int INF = (1 << 30);
• BigInteger negate() //Returns a BigInteger whose
const int MAXN = 200;
value is (-this)
int Elementos[MAXN][MAXN], X[MAXN];
int MP[MAXN];
char vis[MAXN];
42
int NN, MM, dif; }
typedef pair<int, int> Arista; if (t < r.size()) {
// Emparejamiento de costo maximo en grafo visitado[t = r[t]] = true;
bipartito ponderado. if (pareja[t] == -1) {
// Nodos con indice del 0 al n - 1. Recibe los emparejado = true;
mismos parametros for (int p; ; t = p) {
// que MaxEmparejamientoBipartito. Utiliza pareja[t] = retorno[t];
algoritmo hungaro. p = pareja[retorno[t]];
// Cuidado: Se ocupa una matriz de costo entre pareja[retorno[t]] = t;
nodos. if (retorno[t] == l[i])
break;
int slack[MAXN]; }
int retorno[MAXN]; } else {
int etiqueta[MAXN]; visitado[t = pareja[t]] = true;
int pareja[MAXN]; for (int k = 0; k < r.size();
bool visitado[MAXN]; ++k) {
int costo[MAXN][MAXN]; int new_slack = etiqueta[t]
+
long long EmparejaCostoMaxBipartito( etiqueta[r[k]] -
const vector<int>& l, const vector<int>& r) { costo[t][r[k]];
// Si l.size() != r.size() KABOOM! if (new_slack <
assert(l.size() == r.size()); slack[r[k]]) {
slack[r[k]] =
int n = l.size() + r.size(); new_slack;
fill(pareja, pareja + n, -1); retorno[r[k]] = t;
fill(etiqueta, etiqueta + n, 0); }
for (int i = 0; i < l.size(); ++i) }
for (int j = 0; j < r.size(); ++j) }
etiqueta[l[i]] = max(etiqueta[l[i]], } else {
costo[l[i]][r[j]]); int d = INF;
for (int k = 0; k < r.size(); ++k)
for (int i = 0; i < l.size(); ++i) { if (slack[r[k]]) d = min(d,
for (int j = 0; j < r.size(); ++j) slack[r[k]]);
slack[r[j]] = -costo[l[i]][r[j]] + for (int k = 0; k < l.size(); ++k)
etiqueta[l[i]] + etiqueta[r[j]]; if (visitado[l[k]])
fill(visitado, visitado + n, false); etiqueta[l[k]] -= d;
fill(retorno, retorno + n, l[i]); for (int k = 0; k < r.size(); ++k)
visitado[l[i]] = true; if (!visitado[r[k]])
slack[r[k]] -= d;
bool emparejado = false; else etiqueta[r[k]] += d;
for (int j = 0; !emparejado; ++j) { }
int t = 0; for (; t < r.size(); ++t) { }
if (visitado[r[t]]) continue; }
if (!slack[r[t]]) break; long long tot = 0;
43
for (int i = 0; i < l.size(); ++i) vis[k] = 1;
tot += (long }
long)costo[l[i]][pareja[l[i]]]; }
return tot; }
} }
int main(){
//Obtiene el peso del subconjunto de peso maximo cin.tie(0);
tal que es menor o igual a un peso maximo ios_base::sync_with_stdio(0);
determinado int T, N, M;
//Elementos de valor unitario y paso variable
// N - 2 ^ (N/2) cin >> T;
//Meet in the middle for (int nc = 0; nc < T; ++nc) {
int DPA[(1 << 16)], DPB[(1 << 16)]; cin >> N >> M;
void MITM(int N, int M) { vector<int> left, right;
//Subarreglo A [0, (N + 1) / 2] NN = max(N, M);
//Subarreglo B [((N + 1) / 2) + 1, N] for (int i = 0; i < NN; i++) {
set<int> CombinacionesA; left.push_back(i);
for (int i = 0; i < M; ++i) { right.push_back(i + NN);
DPA[0] = DPB[0] = 0; }
int mid_i = X[i] >> 1;
int temp = 1 << mid_i, sum; for (int i = 0; i < N; ++i) cin >>
CombinacionesA.clear(); MP[i];
for (int j = 0; j < mid_i; ++j) DPA[1 << for (int i = 0; i < M; ++i) {
j] = Elementos[i][j]; cin >> X[i];
for (int j = 0; j < X[i] - mid_i; ++j) for (int j = 0; j < X[i]; ++j)
DPB[1 << j] = Elementos[i][mid_i + j]; cin >> Elementos[i][j];
for (int j = 0; j < temp; ++j) { }
int ind = j & (-j); for (int i = 0; i < (NN + NN); ++i)
DPA[j] = DPA[j ^ ind] + DPA[ind]; for (int j = 0; j < (NN + NN); ++j)
CombinacionesA.insert(DPA[j]); costo[i][j] = 0;
} MITM(N, M);
int mid_j = (X[i] - mid_i); cout << EmparejaCostoMaxBipartito(left,
temp = 1 << mid_j; right) << ‘\n’;
char vis[55]; }
fill(vis, vis + N, 0); return 0;
for (int j = 0; j < temp; ++j) { }
int ind = j & (-j);
DPB[j] = DPB[j ^ ind] + DPB[ind];
for (int k = 0; k < N; ++k)
if ((CombinacionesA.find(MP[k]
- DPB[j]) != CombinacionesA.end()) && (vis[k] ==
0)) {
costo[k][NN + i] = MP[k];
44
while (!q.empty()) {
Joutong
Travels
int u = q.front(); q.pop();
//3329 - Compresion de grafo ponderado a subgrafo for (int i = 0; i < grafo[u].size();
ponderado con aristas pertecientes al camino mínimo ++i) {
con Dijkstra int v = grafo[u][i];
if (flujo[u][v] == cap[u][v] ||
#include <bits/stdc++.h>
dist[v] <= dist[u] + 1)
using namespace std;
const int MAXN = 105; continue;
const int INF = (1 << 30); dist[v] = dist[u] + 1, q.push(v);
typedef pair<int, int> Arista; }
}
vector<int> grafo[MAXN];
if (dist[t] < INF) flujo_maximo +=
vector<Arista> grafo_peso[MAXN];
int dist[MAXN]; FlujoBloqueante(s, t, INF);
}
int cap[MAXN][MAXN]; return flujo_maximo;
}
int flujo[MAXN][MAXN];
45
for (int i = 0; i < M; ++i) { LIS
NON-‐DECREASING
cin >> a >> b >> p;
// for reconstructing the answer just check the
a--; b--;
last for in LIS()
grafo_peso[a].push_back(Arista(p, b));
//LIS NON-DECREASING <=
grafo_peso[b].push_back(Arista(p, a));
#include <bits/stdc++.h>
}
using namespace std;
vector<int> distAZ = Dijkstra(A, N);
typedef vector<int> vi;
daz = distAZ[Z];
typedef pair<int, int> pii;
vector<int> distZA = Dijkstra(Z, N);
typedef vector<pii> vpii;
for (int i = 0; i < N; ++i) {
int LIS (vi &v) {
int du = distAZ[i];
vpii best;
for (int j = 0; j < grafo_peso[i].size();
vi dad(v.size(), -1);
++j) {
for (int i = 0; i < v.size(); i++) {
int v = grafo_peso[i][j].second;
pii item = pii(v[i], i);
int p = grafo_peso[i][j].first;
auto it = lower_bound(best.begin(),
if ((du + p) == (daz - distZA[v]))
best.end(), item);
AgregarArista(i, v, 1);
if (it == best.end()) {
}
dad[i] = ((best.size() == 0)? -1:
}
best.back().second);
/* cout << “Grafo original:\n”;
best.push_back(item);
for (int i = 0; i < N; ++i) {
} else {
cout << “NODO “ << i + 1<< “: “;
dad[i] = dad[it->second];
for (int j = 0; j < grafo_peso[i].size();
*it = item;
++j) {
}
cout << “( “ << grafo_peso[i][j].second
}
+ 1<< “ | “ << grafo_peso[i][j].first << “ ) “;
int r, i = best.back().second;
}
for (r = 0; i >= 0; ++r, i = dad[i]);
cout << ‘\n’;
return r;
}
}
cout << “Grafo reducido:\n”;
for (int i = 0; i < N; ++i) {
int main() {
cout << “NODO “ << i + 1<< “: “;
cin.tie(0);
for (int j = 0; j < grafo[i].size(); ++j) {
ios_base::sync_with_stdio(0);
cout << grafo[i][j] + 1<< “ “;
int nc, N, a;
}
//cin >> nc;
cout << ‘\n’;
//while (nc--) {
}*/
cin >> N;
cout << Dinic(A, Z, N) << ‘\n’;
vi v(N);
return 0;
for(int i = 0; i < N; i++) cin >> v[i];
}
cout << LIS(v) << ‘\n’;
//}
return 0;
}
46
LIS
STRICTLY
INCREASING
Unique
Path
// for reconstructing the answer just check the //Componentes Biconexas en grafo bidireccional
last for in LIS() #include <bits/stdc++.h>
//LIS STRICTLY INCREASING using namespace std;
#include <bits/stdc++.h>
using namespace std; // Definiciones iniciales
typedef vector<int> vi; typedef pair<int, int> Arista;
typedef pair<int, int> pii; const int INF = 1 << 30;
typedef vector<pii> vpii; const int MAXN = 100000;
int LIS (vi &v) { vector<int> grafo[MAXN];
vpii best; int numeracion;
vi dad(v.size(), -1); int level[MAXN];
for (int i = 0; i < v.size(); i++) { int parent[MAXN];
pii item = pii(v[i], i); vector<int> puentes[MAXN];
auto it = lower_bound(best.begin(), int low[MAXN], num[MAXN];
best.end(), item); set<Arista> Puentesp;
if (it == best.end()){ // Detecta los puentes y puntos de articulacion en
if ((best.size()) && (item.first == // un grafo bidireccional. Indices de 0 a n - 1.
best.back().first)) { void PuntosArtPuentes_(int u, int p) {
dad[i] = //int hijos = 0;
dad[best.back().second]; low[u] = num[u] = ++numeracion;
best.back() = item; for (int i = 0; i < grafo[u].size(); ++i) {
continue; int v = grafo[u][i];
} if (v == p) continue;
dad[i] = ((best.size() == 0)? -1: if (!num[v]) {
best.back().second); //++hijos;
best.push_back(item); PuntosArtPuentes_(v, u);
} else { if (low[v] > num[u]) {
auto itt = it; puentes[u].push_back(v);
itt--; puentes[v].push_back(u);
if ((it != best.begin()) && }
(item.first == (*itt).first)) { low[u] = min(low[u], low[v]);
dad[i] = dad[(*itt).second]; //punto_art[u] |= low[v] >= num[u];
continue; } else low[u] = min(low[u], num[v]);
} }
dad[i] = dad[it->second]; //if (p == -1) punto_art[u] = hijos > 1;
*it = item; }
}
} void PuntosArtPuentes(int n) {
int r, i = best.back().second; numeracion = 0;
for (r = 0; i >= 0; ++r, i = dad[i]); fill(num, num + n, 0);
return r; fill(low, low + n, 0);
} //fill(punto_art, punto_art + n, false);
47
for (int i = 0; i < n; ++i) puentes[i].clear(); char TC[MAXN];
for (int i = 0; i < n; ++i) char PROC[MAXN];
if (!num[i]) PuntosArtPuentes_(i, -1);
for (int i = 0; i < n; ++i) void Limpia(int n){
for (int j = 0; j < puentes[i].size(); ++j) for (int i = 0; i < n; ++i) {
Puentesp.insert(Arista(i, grafo[i].clear();
puentes[i][j])); PROC[i] = ‘N’;
} }
// Estructura de conjuntos disjuntos. Puentesp.clear();
// Conjuntos indexados de 0 a n - 1. }
48
for (int j = 0; j < puentes[i].size();
++j) { File
Transmission
int v = puentes[i][j]; //Compresion de grafo bidireccional a arbol
if ((TC[i] == ‘C’) || (TC[v] == #include <bits/stdc++.h>
‘C’)) continue; using namespace std;
//cout << “Puente entre: “ << i +1
const int MAXN = 10005;
<< “ y “ << v + 1 << ‘\n’;
const int LOGN = 18;
UF.Unir(i, v); vector<int> grafo[MAXN];
} typedef pair<int, int> Arista;
} char vis[MAXN];
long long ans = 0, aux;
int numeracion;
//proc N = NOT DOMN, D = DONE;
int level[MAXN];
for (int i = 0; i < N; ++i) { int parent[MAXN];
int pi = UF.Encontrar(i); vector<int> puentes[MAXN];
if ((TC[i] == ‘S’) && (PROC[pi] == int low[MAXN], num[MAXN], P[MAXN][LOGN];
‘N’)) {
set<Arista> Puentesp;
aux = UF.TamanoConjunto(i);
// Detecta los puentes y puntos de articulacion en
ans += ((aux * (aux - 1)) / 2); // un grafo bidireccional. Indices de 0 a n - 1.
PROC[pi] = ‘D’;
} void PuntosArtPuentes_(int u, int p) {
}
//int hijos = 0;
cout << “Case #” << nc << “: “ << ans <<
low[u] = num[u] = ++numeracion;
‘\n’; for (int i = 0; i < grafo[u].size(); ++i) {
} int v = grafo[u][i];
return 0; if (v == p) continue;
}
if (!num[v]) {
//++hijos;
PuntosArtPuentes_(v, u);
if (low[v] > num[u]) {
puentes[u].push_back(v);
puentes[v].push_back(u);
}
low[u] = min(low[u], low[v]);
//punto_art[u] |= low[v] >= num[u];
} else low[u] = min(low[u], num[v]);
}
//if (p == -1) punto_art[u] = hijos > 1;
}
void PuntosArtPuentes(int n) {
numeracion = 0;
fill(num, num + n, 0);
fill(low, low + n, 0);
49
//fill(punto_art, punto_art + n, false); };
for (int i = 0; i < n; ++i) puentes[i].clear();
for (int i = 0; i < n; ++i)
if (!num[i]) PuntosArtPuentes_(i, -1); void PRE(int n) {
for (int i = 0; i < n; ++i) for (int d = 1; d < LOGN; ++d)
for (int j = 0; j < puentes[i].size(); ++j) for (int i = 0; i < n; ++i)
Puentesp.insert(Arista(i, P[i][d] = P[P[i][d - 1]][d - 1];
puentes[i][j])); }
}
int lca(int u, int v) {
// Estructura de conjuntos disjuntos. if (level[u] > level[v]) swap(u, v);
// Conjuntos indexados de 0 a n - 1. for (int i = 0, j = level[v] - level[u]; i <
LOGN && j > 0; ++i, j >>= 1)
struct UnionFind { if (j & 1) v = P[v][i];
int nconjuntos; if (u == v) return u;
vector<int> padre; for (int i = LOGN - 1; i >= 0; --i)
vector<int> tamano; if (P[u][i] != P[v][i]) {
u = P[u][i];
UnionFind(int n) : nconjuntos(n), v = P[v][i];
padre(n), tamano(n, 1) { }
for(int i = 0; i < n; ++i) return P[u][0];
padre[i] = i; }
}
void Limpia(int n) {
int Encontrar(int u) { for (int d = 0; d < LOGN; ++d)
if (padre[u] == u) return u; for (int i = 0; i < n; ++i) P[i][d] = 0;
return padre[u] = Encontrar(padre[u]); for (int i = 0; i < n; ++i) {
} vis[i] = 0;
grafo[i].clear();
void Unir(int u, int v) { P[i][0] = i;
int Ru = Encontrar(u); level[i] = 1;
int Rv = Encontrar(v); }
if (Ru == Rv) return; Puentesp.clear();
-- nconjuntos, padre[Ru] = Rv; }
tamano[Rv] += tamano[Ru];
} void Regiones(int n, UnionFind& UF) {
for (int i = 0; i < n; ++i)
bool MismoConjunto(int u, int v) { for (int j = 0; j < grafo[i].size(); ++j) {
return Encontrar(u) == Encontrar(v); int v = grafo[i][j];
} if (Puentesp.find(Arista(i, v)) !=
Puentesp.end()) continue;
int TamanoConjunto(int u) { UF.Unir(i, v);
return tamano[Encontrar(u)]; }
} }
50
void Enraizar(int o, UnionFind UF) { for (int i = 0; i < N; ++i) {
queue<int> Q; cout << “NODO “ << i + 1 << “: “;
Q.push(o); for (int j = 0; j < grafo[i].size();
vis[o] = 1; ++j) cout << grafo[i][j] + 1<< “ “;
while (!Q.empty()) { cout << ‘\n’;
int u = Q.front(); }*/
int pu = UF.Encontrar(u); //for (int i = 0; i < N; ++i) UF.Unir(i,
//cout << “sale “ << u << ‘\n’; low[i] - 1);
Q.pop(); //for (int i = 0; i < N; ++i) cout <<
for (int j = 0 ; j < grafo[u].size(); ++j) “Padre - Region de “ << i + 1 << “: “ <<
{ UF.Encontrar(i) + 1 << ‘\n’;
int v = grafo[u][j]; Enraizar(0, UF);
int pv = UF.Encontrar(v); /*for (int i = 0; i < N; ++i) {
if (vis[v] == 1) continue; for (int j = 0 ; j < grafo[i].size();
if (pv != pu) { ++j) {
level[pv] = level[pu] + 1; int v = grafo[i][j];
P[pv][0] = pu; int pu = UF.Encontrar(i);
} int pv = UF.Encontrar(v);
vis[v] = 1; if ((pu == pv) || (vis[pv] == 1))
Q.push(v); continue;
} level[pv] += level[pu];
} P[pv][0] = pu;
} vis[pv] = 1;
int main(){ vis[pu] = 1;
cin.tie(0); }
ios_base::sync_with_stdio(0); }*/
int N, M; //for (int i = 0; i < N; ++i) cout <<
for (int nc = 1; ; ++nc) { “level de “ << i + 1 << “ cuyo padre es: “ <<
cin >> N >> M; UF.Encontrar(i) + 1 << “ = “ <<
if (N + M == 0) break; level[UF.Encontrar(i)] << ‘\n’;
Limpia(N); PRE(N); int Q; cin >> Q;
int a, b; if (nc > 1) cout << ‘\n’;
for (int i = 0; i < M; ++i) { cout << “Case #” << nc << “:\n”;
cin >> a >> b; for (int i = 0; i < Q; ++i) {
a--; b--; cin >> a >> b;
grafo[a].push_back(b); a--; b--;
grafo[b].push_back(a); int pa = UF.Encontrar(a);
} int pb = UF.Encontrar(b);
PuntosArtPuentes(N); long long ans = (level[pa] + level[pb]
UnionFind UF(N); - ((level[lca(pa, pb)]) << 1)) * 50LL ;
Regiones(N, UF); cout << ans << ‘\n’;
//for (int i = 0; i < N; ++i) cout << “NODO }
“ << i + 1 << “ REGION: “ << low[i] << ‘\n’; }
/*cout << “GRAFOOO!!\n”; return 0; }
51