Herramientas de usuario

Herramientas del sitio


algoritmos-oia:estructuras:tablita-aditiva

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
algoritmos-oia:estructuras:tablita-aditiva [2017/12/11 14:29]
ariel [El caso de dos dimensiones]
algoritmos-oia:estructuras:tablita-aditiva [2018/01/06 00:13] (actual)
ariel
Línea 24: Línea 24:
 Si nos llega la consula $a$, $b$, queremos sumar los números en posiciones menores a $b$ y mayores o iguales a $a$. En S[b] tenemos la suma de los números en posiciones menores a $b$, pero estamos sumando números de más. Nos sobran los números en posiciones menores a $a$ ¡Pero esto es justamente S[a]! Luego, podemos dar la respuesta como S[b] - S[a]. Si nos llega la consula $a$, $b$, queremos sumar los números en posiciones menores a $b$ y mayores o iguales a $a$. En S[b] tenemos la suma de los números en posiciones menores a $b$, pero estamos sumando números de más. Nos sobran los números en posiciones menores a $a$ ¡Pero esto es justamente S[a]! Luego, podemos dar la respuesta como S[b] - S[a].
  
-FIXME: Insertar dibujito lindo.+$$\overbrace{\underbrace{A[0] + A[1] + \ldots + A[a-1]}_{s[a]} + \underbrace{A[a] + A[a+1] + \ldots + A[b-1]}_{s[b]-s[a]}}^{s[b]}$$
  
 Con esto podemos responder cada consulta en $O(1)$, tardando en total $O(q)$ en responder todas. Todavía nos queda el problema de calcular S eficientemente,​ ya que el algoritmo que consiste en calcular cada elemento de S sumando todos los números del intervalo correspondiente es $O(n^2)$. Con esto podemos responder cada consulta en $O(1)$, tardando en total $O(q)$ en responder todas. Todavía nos queda el problema de calcular S eficientemente,​ ya que el algoritmo que consiste en calcular cada elemento de S sumando todos los números del intervalo correspondiente es $O(n^2)$.
  
 La observación clave es que si queremos calcular el elemento $i$ de S podemos aprovechar que ya calculamos el $i-1$ (si $i>0$), S[i-1] tiene la suma de los números en posiciones menores a la $i-1$, el único que me falta sumar para conseguir S[i] (las posiciones menores a $i$) es el número de la posición $i-1$. Luego, S[i] = S[i-1] + A[i-1]. La observación clave es que si queremos calcular el elemento $i$ de S podemos aprovechar que ya calculamos el $i-1$ (si $i>0$), S[i-1] tiene la suma de los números en posiciones menores a la $i-1$, el único que me falta sumar para conseguir S[i] (las posiciones menores a $i$) es el número de la posición $i-1$. Luego, S[i] = S[i-1] + A[i-1].
 +
 +$$\overbrace{\underbrace{A[0] + A[1] + \ldots + A[i-2]}_{s[i-1]} + A[i-1]}^{s[i]}$$
  
 Usando esta fórmula y que S[0] = 0, podemos calcular el vector S en $O(n)$. Usando esta fórmula y que S[0] = 0, podemos calcular el vector S en $O(n)$.
Línea 62: Línea 64:
 Ahora, dada una consulta $a, b, c, d$, podemos responder la consulta en $O(1)$ usando S como S[c][d] - S[a][d] - S[c][b] + S[a][b]. Ahora, dada una consulta $a, b, c, d$, podemos responder la consulta en $O(1)$ usando S como S[c][d] - S[a][d] - S[c][b] + S[a][b].
  
-Para calcular S eficientemente,​ hay varias maneras, una de ellas es notar que S[i][j] = S[i-1][j] + S[i][j-1] - S[i-1][j-1] + A[i-1][j-1] (si $i>0$ y $j>0$).+Para calcular S eficientemente,​ hay varias maneras, una de ellas es notar que S[i][j] = S[i-1][j] + S[i][j-1] - S[i-1][j-1] + A[i-1][j-1] (si $i,j>0$)
 + 
 +FIXME: Agregar dibujos explicativos.
  
 Usando estas dos observaciones podemos calcular S en $O(nm)$ y responder todas las consultas en $O(q)$. Usando estas dos observaciones podemos calcular S en $O(nm)$ y responder todas las consultas en $O(q)$.
 +
 +=== Implementación ===
 +
 +<code cpp>
 +void sumasSubrectangulos(vector<​vector<​long long>>​ M){
 + int n = M.size(); //cantidad de filas
 +        int m = M[0].size();​ //cantidad de columnas (ojo si n = 0)
 +        vector<​vector<​long long>>​ S(n+1, vector<​long long>​(m+1,​ 0)); //S de tamaño n+1 x m+1 inicializado en 0
 +        for(int i = 1; i <= n; i++) {
 +            for(int j = 1; j <= m; j++) {
 +                S[i][j] = S[i-1][j] + S[i][j-1] - S[i-1][j-1] + A[i-1][j-1];​
 +            }
 +        }
 +        ​
 +        int q; //cantidad de consultas
 +        cin >> q;
 +        for(int i = 0; i < q; i++) {
 +            int a, b, c, d;
 +            cin >> a >> b >> c >> d;
 +            cout << S[c][d] - S[a][d] - S[c][b] + S[a][b];
 +        }
 +}
 +</​code>​
 +
  
 FIXME: Explicar el problema en más dimensiones. FIXME: Explicar el problema en más dimensiones.
algoritmos-oia/estructuras/tablita-aditiva.1513002571.txt.gz · Última modificación: 2017/12/11 14:29 por ariel