#A. Enfileiramento de escalação balanceada (pergunta do modelo rmq)

tema


linha de raciocínio

Recomenda-se examinar primeiro a explicação detalhada do problema rmq .

Obviamente, esta questão tem como objetivo acompanhar uma série de números, e dar múltiplas consultas, perguntando sobre a diferença entre os valores máximo e mínimo no intervalo.

Se você for para a enumeração violenta, obviamente o tempo expirará, então use o algoritmo st para resolvê-lo.

Criaremos dois conteúdos de pré-processamento RMQ para lidar com o valor máximo e o valor mínimo, respectivamente.

Crie um mx[i][j] para representar o valor máximo no intervalo começando em i e comprimento 2^j, e mn[i][j] para representar o valor mínimo no intervalo começando em i e comprimento 2^j .

De acordo com a ideia de duplicação, um intervalo com comprimento de 2^j pode ser dividido em dois subintervalos com comprimento de 2^(j-1), e então o valor máximo dos dois subintervalos pode ser encontrado. Portanto, durante o pré-processamento, o intervalo é dividido em duas partes uniformemente a partir do meio (não importa se há sobreposição no meio, e isso não afeta o valor máximo), e o número de elementos em cada parte é exatamente 2 ^ j-1, ou seja, a equação de transição de estado é:

mx[j][i] = max(mx[j][i - 1],mx[j + s[i - 1]][i - 1])

mn[j][i] = min(mn[j][i - 1],mn[j + s[i - 1]][i - 1])

(s[i] representa 2^i potência)

Se F[i, j] representa o valor máximo do intervalo [i, i+2^j-1], e o comprimento do intervalo é 2^j, qual é o intervalo de valores de i e j?

Se o comprimento da matriz for n e o comprimento máximo do intervalo for 2^r≤n<2^(r+1), então r=⌊log2n⌋, por exemplo, k=3 quando n=8, e k= 3 quando n=10. No programa, r=log2(n), i from 1~i<=r, j from 1~s[i]+j-1<=n (porque i representa a duração do intervalo e j representa o início posição do intervalo)

Código de pré-processamento:

void pre()
{
  int r = log2(n);
  for(int i = 1; i <= r; i++)
    for(int j = 1; s[i] + j - 1 <= n; j++)
    {
      mx[j][i] = max(mx[j][i - 1],mx[j + s[i - 1]][i - 1]);
      mn[j][i] = min(mn[j][i - 1],mn[j + s[i - 1]][i - 1]);
    }
}

Após o pré-processamento, é hora de iniciar a consulta.

Se você consultar os valores máximo e mínimo do intervalo [l,r], primeiro calcule o valor k, que é igual ao método de cálculo anterior, e a duração do intervalo é rl+1.

2^k≤r-l+1<2^(k+1), então k=log2(rl+1).

Se o comprimento do intervalo de consulta for maior ou igual a 2^k e menor que 2^(k+1), então, de acordo com a ideia de multiplicação, o intervalo de consulta pode ser dividido em dois intervalos de consulta, e o valor máximo de os dois intervalos podem ser tomados. Os dois intervalos são 2 ^ k números para trás a partir de L e 2 ^ k números para frente a partir de R. Esses dois intervalos podem se sobrepor, mas não têm efeito na localização do valor máximo.

查询代码:

int f(int x,int y)
{
  int r = log2(y - x + 1);
  int t1 = max(mx[x][r],mx[y - s[r] + 1][r]);
  int t2 = min(mn[x][r],mn[y - s[r] + 1][r]);
  return t1 - t2;
}

整体代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,q,a[1000001],mx[1000001][20],mn[1000001][20],s[1000001],x,y;
void pre()
{
  int r = log2(n);
  for(int i = 1; i <= r; i++)
    for(int j = 1; s[i] + j - 1 <= n; j++)
    {
      mx[j][i] = max(mx[j][i - 1],mx[j + s[i - 1]][i - 1]);
      mn[j][i] = min(mn[j][i - 1],mn[j + s[i - 1]][i - 1]);
    }
}
int f(int x,int y)
{
  int r = log2(y - x + 1);
  int t1 = max(mx[x][r],mx[y - s[r] + 1][r]);//最大
  int t2 = min(mn[x][r],mn[y - s[r] + 1][r]);//最小
  return t1 - t2;//差
}
signed main()
{
  s[0] = 1;
  for(int i = 1; i <= 20; i++) s[i] = s[i - 1] * 2;//s[i]代表2^i次方
  scanf("%lld%lld",&n,&q);
  for(int i = 1; i <= n; i++)
  {
    scanf("%lld",&t);
    mx[i][0] = mn[i][0] = t;//初始化,从第i个位置向后延2^0位的最大值和最小值都是输入的第i个位置上的数
  }
  pre();//预处理
  for(int i = 1; i <= q; i++)
  {
    scanf("%lld%lld",&x,&y);
    printf("%lld\n",f(x,y));//查询
  }
  return 0;
}

Acho que você gosta

Origin blog.csdn.net/weq2011/article/details/128767164
Recomendado
Clasificación