Está en la página 1de 51

 

 
The Reference
 

 
 
 
     

Sponsored by: Alichos, itan, el monstruo, el tío Ed, el


itan x2, el garo y Jhon Cena.
Contenido   Definición  Polígono  ...................................................................................  10  
bool  PuntoEnPerimetro(const  Punto&  p,  const  Poligono&  P)  ...  11  
STL  .............................................................................................................  4   int  PuntoEnConvexo(const  Punto&  p,  const  Poligono&  P)  ..........  11  
C++  .....................................................................................................................  4   int  RayCasting(const  Punto&  p,  const  Poligono&  P)  ......................  11  
C++11  ...............................................................................................................  5   int  AngleSummation(const  Punto&  p,  const  Poligono&  P)  ..........  11  
C++  STL  Algorithms  .....................................................................................  5   double  Area(const  Poligono&  P)  ..........................................................  11  
double  Perimetro(const  Poligono&  P)  ...............................................  11  
Geometría  ................................................................................................  6   Poligono  CercoConvexo(vector<Punto>  P)  .......................................  12  
Estructura  Punto  ..........................................................................................  6   Punto  Centroide(const  Poligono&  P)  ..................................................  12  
double  Distancia(const  Punto&  p,  const  Punto&  q)  .........................  6   bool  RectaCortaPoligono(  const  Linea&  r,  const  Poligono&  P)  ..  12  
double  Magnitud(const  Punto&  v)  .........................................................  6   vector<Poligono>  CortarPoligono(const  Poligono&  P,  const  
double  Dot(const  Punto&  v,  const  Punto&  w)  ....................................  6   Linea&  r)  .......................................................................................................  12  
double  Cruz(const  Punto&  v,  const  Punto&  w)  ..................................  6   Estructura  Círculo  ......................................................................................  13  
double  GradARad(double  grd)  ................................................................  6   double  Circuferencia(const  Circulo&  c)  .............................................  13  
double  RadAGrad(double  rad)  ................................................................  6   double  Area(const  Circulo&  c)  ..............................................................  13  
Punto  Rotar(const  Punto&  p,  double  rad)  ...........................................  6   int  PuntoEnCirculo(const  Punto&  p,const  Circulo&  c)  ..................  13  
Punto  Trasladar(const  Punto&  o,  const  Punto&  p)  ..........................  6   double  DistanciaPuntoCirculo(const  Punto&  p,  const  Circulo&  c)
Punto  Escalar(const  Punto&  v,  double  s)  .............................................  7    ..........................................................................................................................  13  
Punto  Opuesto(const  Punto&  v)  ..............................................................  7   Punto  ProyPuntoCircunferencia(const  Punto&  p,  const  Circulo&  
double  Angulo(const  Punto&  v,  const  Punto&  w)  .............................  7   c)  ......................................................................................................................  13  
int  ManoDerecha(const  Punto&  o,  const  Punto&  p,  const  Punto&   Linea  ProyTangentes(const  Punto&  p,  const  Circulo&  c)  ............  13  
q)  ........................................................................................................................  7   int  IntersecCirculoRecta(const  Circulo&  c,  const  Linea&  r)  ........  13  
pair<Punto,  Punto>  ParMasCercano(vector<Punto>  P)  .................  7   Punto  Chicharronera(double  a,  double  b,  double  c)  ......................  14  
Estructura  Linea  ...........................................................................................  7   Linea  CuerdaInterseccion(const  Circulo&  c,  const  Linea&  r)  .....  14  
bool  PuntoEnRecta(const  Punto&  p,  const  Linea&  r)  ......................  8   bool  CirculoEnCirculo(const  Circulo&  c,  const  Circulo&  d)  .........  14  
bool  PuntoEnSegmento(constPunto  p,const  Linea&s)  ....................  8   int  IntersecCirculoCirculo(const  Circulo&  c,  const  Circulo&  d)  .  14  
bool  LineasParalelas(const  Linea&l,  const  Linea&m)  .....................  8  
bool  LineasIguales(const  Linea&  l,  const  Linea&  m)  .......................  8   Grafos  .....................................................................................................  17  
bool  LineasPerpendiculares(  const  Linea&  l  ,const  Linea&  m)  ....  9   Definiciones  Iniciales  ...............................................................................  17  
Linea  ParalelaEnPunto(  const  Linea&  l,  const  Punto&  p)  ..............  9   Estructura  Grafo  .........................................................................................  17  
Linea  PerpendicularEnPunto(const  Linea&  l,  const  Punto&  p)  ...  9   Detectar  Ciclos  ............................................................................................  17  
int  InterseccionRectas(const  Linea&r,const  Linea&s)  ....................  9   Puentes  y  Puntos  de  Articulación  .........................................................  17  
}int  IntersecRectaSegmen(const  Linea&  r,  const  Linea&  s)  ..........  9   Componentes  Fuertemente  Conexas  ...................................................  18  
int  InterseccionSegmentos(const  Linea&  s,  const  Linea&  t)  .........  9   EsBipartito  ...................................................................................................  18  
Punto  PuntoInterseccion(const  Linea&  l,  const  Linea&  m)  ........  10   Orden  Topológico  ......................................................................................  18  
Punto  ProyeccionEnRecta(const  Punto&  v,  const  Linea&  r)  ......  10   BFS  ..................................................................................................................  19  
double  DistanciaPuntoRecta(const  Punto&  p,  const  Linea&  r)  .  10   Union-­‐Find  ....................................................................................................  19  
double  DistanciaPuntoSegmento(const  Punto&  p,  const  Linea&   GrafoCosto  ....................................................................................................  19  
s)  .....................................................................................................................  10   Kruskal  ..........................................................................................................  20  
double  DistanciaRectaRecta(const  Linea&  l,  const  Linea&  m)  ..  10   Dijkstra  ..........................................................................................................  20  
double  DistanciaSegmenSegmen(const  Linea&  s,  const  Linea&  r) BellmanFerrari  ...........................................................................................  20  
 .........................................................................................................................  10  
Árboles  ..................................................................................................  21  

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>:  

queue<T> Q // O(1) bitset<n> B // O(1)


Q.push(T) // O(1) B.count() //Count bits set
Q.pop() // O(1) B.any() // Test if any bit is set
Q.size() // O(1) B.set() //Set bits to 1
Q.front() // O(1) B.set(int pos, bool val = true); // foo.set(2,0)
B.reset() // Resets bits to zero
B.to_ulong() // Convert to unsigned long integer.
Double  Ended  Queue  <deque>:
B[i] = 0 | 1 // O(1)
deque<T> D // O(1)
D.push_back(T) // O(1) Pair  <utility>:  
D.push_front(T) // O(1)
pair<T, T> P // O(1)
D.pop_back() // O(1)
P.first | P.second // O(1)
D.pop_front() // O(1)
make_pair(T, T); // O(1)
D.size() // O(1)
D.back() // O(1)    
D.front() // O(1)
D.clear() // O(n)

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)

C++11 Next  /  Previous  Permutation:    


Unordered  Map  <unordered_map>    
next_permutation(array, array + n) // O(n)
unordered_map <K,V> M; //O(1) prev_permutation(array, array + n) // O(n)
M[K] = V // O(1)
M.count(K) //O(n) Minimum / Maximum:
M.clear() //O(n) min(T, T) // O(1)
Unordered  Set  <unordered_set>   max(T, T) // O(1)

unordered_set <T> S // O(1)


S.insert( T ) // O(1)
S.erase( T ) // O(n)
S.clear() //O(n)
S.find(T) // O(1)
S.count(T) // O(n)
S.size() // O(1)

C++  STL  Algorithms  


Sort:  

sort(array, array + n) // O(n log n)


sort(vector.begin(), vector.end()) // O(n 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)

Lower  /  Upper  Bound:  


lower_bound(array, array + n, T) // O(log n)
lower_bound(vector.begin(), vector.end(), T)

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;
} }

Estructura  Punto   double  GradARad(double  grd)  


// Punto en 2D. // Conversion de grados a radianes.
struct Punto { double GradARad(double grd) {
return (grd * M_PI) / 180;
double x, y; }
Punto() : x(), y() {}
Punto(double X, double Y) : x(X), y(Y) {}
double  RadAGrad(double  rad)  
// Izquierda a derecha, abajo a arriba. // Conversion de radianes a grados.
bool operator<(const Punto& cmp) const { double RadAGrad(double rad) {
if (!Igual(x, cmp.x)) return x < cmp.x; return (rad * 180) / M_PI;
return Igual(y, cmp.y)? false: y < cmp.y; }
}
Punto  Rotar(const  Punto&  p,  double  rad)  
bool operator==(const Punto& cmp) const { // Rotar un punto respecto al origen.
return Igual(x, cmp.x) && Igual(y, cmp.y); // La rotación se hace en orden CCW, para
} // rotar en CW llamar Rotar(p, M_2PI - rad).
}; Punto Rotar(const Punto& p, double rad) {
return Punto(p.x*cos(rad) - p.y*sin(rad),
double  Distancia(const  Punto&  p,  const  Punto&  q)   p.x*sin(rad) + p.y*cos(rad));
// Distancia entre dos puntos p y q. }
double Distancia(const Punto& p, const Punto& q) {
return hypot(p.x - q.x, p.y - q.y); Punto  Trasladar(const  Punto&  o,  const  Punto&  p)  
} // Trasladar p tomando como origen al punto o .
Punto Trasladar(const Punto& o, const Punto& p) {
double  Magnitud(const  Punto&  v)   return Punto(p.x - o.x, p.y - o.y);
// Magnitud de un vector v. }
double Magnitud(const Punto& v) {
return hypot(v.x, v.y);
}

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.

typedef vector<Punto> Poligono;

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;
} }

int  PuntoEnConvexo(const  Punto&  p,  const   double  Area(const  Poligono&  P)  


Poligono&  P)   // Area de un poligono.
double Area(const Poligono& P) {
// Prueba de punto en poligono convexo. double area = 0;
// En el perimetro = -1, Fuera = 0, Dentro = 1. for (int i = 1; i < P.size(); ++i)
int PuntoEnConvexo(const Punto& p, area += Cruz(P[i - 1], P[i]);
const Poligono& P) { return fabs(area) / 2.0;
if (PuntoEnPerimetro(p, P)) return -1; }
int dir = ManoDerecha(P[0], P[1], p);
for (int i = 2; i < P.size(); ++i)
if (ManoDerecha(P[i - 1], P[i], p) != dir) double  Perimetro(const  Poligono&  P)  
return 0; // Fuera. // Perimetro de un poligono.
return 1; // Dentro. double Perimetro(const Poligono& P) {
} double perimetro = 0;
for (int i = 1; i < P.size(); ++i)
int  RayCasting(const  Punto&  p,  const  Poligono&  P)   perimetro += Distancia(P[i - 1], P[i]);
return perimetro;
// Punto en poligono concavo por ray casting. }
// En el perimetro = -1, Fuera = 0, Dentro = 1.
int RayCasting(const Punto& p, const Poligono& P) {
if (PuntoEnPerimetro(p, P)) return -1;
Punto o = *min_element(P.begin(), P.end());
Linea rayo(p, Punto(o.x - M_PI, o.y - M_E));
int cruces = 0;
for (int i = 1; i < P.size(); ++i)
if (InterseccionSegmentos(rayo,
Linea(P[i - 1], P[i]))) ++cruces;
return cruces & 1;
}

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];
} }

BFS   int Tamano(int u) {


return tam[Raiz(u)];
// Busqueda en amplitud 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.
vector<Costo> BFS(int s) { GrafoCosto  
queue<int> q;
vector<Costo> d(n, INF); typedef pair<Costo, int> CostoNodo;
q.push(s), d[s] = 0; typedef pair<Costo, Arista> Ponderada;
while (!q.empty()) {
int u = q.front(); q.pop(); // Grafos con ponderacion.
for (int v : ady[u]) // Nodos indexados de 0 a n - 1.
if (d[u] + 1 < d[v]) // GrafoPonderado(n, true) -> Bidireccional.
d[v] = d[u] + 1, q.push(v); // GrafoPonderado(n, false) -> Dirigido.
}
return d; struct GrafoPonderado {
} int n; bool bi;
}; //Fin Estructura Grafo vector<vector<CostoNodo>> ady;
GrafoPonderado(int N, bool B = true): n(N),
Union-­‐Find   bi(B), ady(N) {}
// Conjuntos disjuntos con Union-Find.
void AgregarArista(int u, int v, Costo c) {
struct UnionFind {
if (bi) ady[v].push_back(CostoNodo(c, u));
int n; vector<int> padre, tam;
ady[u].push_back(CostoNodo(c, v));
UnionFind(int N) : n(N), tam(N, 1), padre(N) {
}
while (--N) padre[N] = N;
}

int Raiz(int u) {
if (padre[u] == u) return u;
return padre[u] = Raiz(padre[u]);
}

bool SonConexos(int u, int v) {


return Raiz(u) == Raiz(v);
}

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

void AgregarArista(int u, int v, int c){ vector<int> Dijkstra(int o, int n) {


grafo[u].push_back(v); vector<int> dista(n, INF);
grafo[v].push_back(u); priority_queue<Arista, vector<Arista>,
greater<Arista> > pq;
cap[u][v] += c; cap[v][u] += c;
pq.push(Arista(0, o)); dista[o] = 0;
//flujo[v][u] += c; // Solo en dirigidas!
} while (!pq.empty()) {
int u = pq.top().second;
int FlujoBloqueante(int u, int t, int f) { int p = pq.top().first; pq.pop();
//if (dist[u] < p) continue;
if (u == t) return f; int fluido = 0;
for (int i = 0; i < grafo_peso[u].size();
for (int i = 0; i < grafo[u].size(); ++i) {
int v = grafo[u][i]; ++i) {
if (dist[u] + 1 > dist[v]) continue; p = grafo_peso[u][i].first;
int fv = FlujoBloqueante(v, t, int v = grafo_peso[u][i].second;
if (dista[u] + p < dista[v]) {
min(f - fluido, cap[u][v] -
dista[v] = dista[u] + p;
flujo[u][v]));
flujo[u][v] += fv; flujo[v][u] -= fv; pq.push(Arista(dista[v], v));
fluido += fv; if (fluido == f) break; }
} }
}
return fluido;
return dista;
}
}
int Dinic(int s, int t, int n) { int main() {
int flujo_maximo = dist[t] = 0; cin.tie(0);
ios_base::sync_with_stdio(0);
while (dist[t] < INF) {
int N, M, A, Z, a, b, p, daz, dza;
fill(dist, dist + n, INF);
queue<int> q; q.push(s); dist[s] = 0; cin >> N >> M >> A >> Z;
A--; Z--;

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. }

struct UnionFind { void Regiones(int n, UnionFind& UF) {


int nconjuntos; for (int i = 0; i < n; ++i)
vector<int> padre; for (int j = 0; j < grafo[i].size(); ++j) {
vector<int> tamano; int v = grafo[i][j];
if (Puentesp.find(Arista(i, v)) !=
UnionFind(int n) : nconjuntos(n), Puentesp.end()) continue;
padre(n), tamano(n, 1) { UF.Unir(i, v);
for(int i = 0; i < n; ++i) }
padre[i] = i; }
} int main(){
cin.tie(0);
int Encontrar(int u) { ios_base::sync_with_stdio(0);
if (padre[u] == u) return u; int T;
return padre[u] = Encontrar(padre[u]); cin >> T;
} for (int nc = 1; nc <= T; ++nc) {
int N, M, a, b;
void Unir(int u, int v) { cin >> N >> M;
int Ru = Encontrar(u); Limpia(N);
int Rv = Encontrar(v); for (int i = 0; i < M; ++i) {
if (Ru == Rv) return; cin >> a >> b;
-- nconjuntos, padre[Ru] = Rv; a--; b--;
tamano[Rv] += tamano[Ru]; grafo[a].push_back(b);
} grafo[b].push_back(a);
}
bool MismoConjunto(int u, int v) { PuntosArtPuentes(N);
return Encontrar(u) == Encontrar(v); UnionFind UFC(N);
} Regiones(N, UFC);
for (int i = 0; i < N; ++i)
int TamanoConjunto(int u) { if (UFC.TamanoConjunto(i) > 1) TC[i] =
return tamano[Encontrar(u)]; ‘C’;
} else TC[i] = ‘S’;
}; UnionFind UF(N);
for (int i = 0; i < N; ++i) {

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

También podría gustarte