Maison  >  Article  >  développement back-end  >  Interrogez le nombre d'éléments d'un tableau supérieurs ou égaux à un nombre donné et mettez-le à jour

Interrogez le nombre d'éléments d'un tableau supérieurs ou égaux à un nombre donné et mettez-le à jour

王林
王林avant
2023-09-05 08:25:12906parcourir

Interrogez le nombre déléments dun tableau supérieurs ou égaux à un nombre donné et mettez-le à jour

Avec l'aide des arborescences de segments, les tableaux peuvent être mis à jour avec succès et les requêtes de plage effectuées. En mettant à jour, nous pouvons utiliser l'arborescence de segments de structure de données connue pour compter. Le nombre d'éléments dans le tableau supérieur ou égal à no.

  • Requête - Recherchez combien d'éléments supérieurs ou similaires à x existent dans la plage [l, r].

    • Donné 0 si la plage [l, r] s'étend complètement au-delà du segment représenté par le nœud actuel de l'arborescence des segments.

    • Compte. Nombre d'éléments dans la plage [l, r] qui sont supérieurs ou similaires à x si l'intervalle [l, r] se situe entièrement dans le segment représenté par le nœud actuel de l'arborescence de segments.

    • Sinon, pingez récursivement les nœuds enfants gauche et droit du nœud actuel, renvoyant le nombre total de décomptes collectés.

  • Mise à jour - Pour l'élément à l'index i, ajoutez la valeur de v. Nous appliquons l'algorithme suivant à cette mise à jour -

    • Si la plage d'affichage des nœuds actuelle de l'arborescence de segments n'a pas d'index i, aucune opération n'est effectuée.

    • Si la valeur de l'index i est supérieure ou égale à x, mettez à jour le nombre d'éléments supérieurs ou égaux à x dans l'intervalle représenté par le nœud actuel de l'arborescence des segments de ligne. Si la valeur de l'index i est supérieure à. ou égal à x, incrémentez-le, puis mettez à jour le nœud actuel de manière récursive. Les nœuds d'éléments enfants gauche et droit.

    • Nous pouvons exécuter des requêtes dans la plage [0, n-1] dans le nœud racine de l'arborescence des segments, où n est le nombre total. Le nombre d'entrées dans le tableau supérieur ou égal à x.

Grammaire

1. Créez des arbres de segments et des tableaux à partir de zéro -

int M; 
int Z[M]; 
int TreE[4*M]; 
BUILD (1, 0, M-1, Z, TreE); 

2. Effectuer la procédure de mise à jour (changement) -

Void change (int NoDe, BeGiN,EnD,IdX,VaL,TreE []) {
   if (BeGiN==EnD) {
      Z[IdX]=VaL;
      TreE[NoDe]=VaL;
   } else {
      int MiD= (BeGiN + EnD)/2;
      if (BeGiN<=IdX && IdX<=MiD)
         change (2*NoDe, BeGiN, MiD, IdX, VaL, TreE);
      else
         change (2*NoDe+1, MiD+1, EnD, IdX, VaL, TreE);
      TreE[NoDe] = TreE[2*NoDe] + TreE[2*NoDe+1];
   }
}

3. Effectuez les opérations de requête suivantes -

int QUERY(int NoDe, BeGiN, EnD, L, R, K, TreE []) {
   if(sTaRT > EnD || BeGiN > R || EnD < L)
      return 0;
   if(BeGiN == EnD)
      return A[BeGiN] >= K;
   int MiD = (BeGiN + EnD) / 2;
   return QUERY(2*NoDe, BeGiN, MiD, L, R, K, TreE) + QUERY (2*NoDe+1, MiD+1, EnD, L, R, K, TreE);
}

4. Utilisez les opérations de requête pour compter les quantités. Éléments supérieurs ou égaux à la valeur spécifiée, opération de mise à jour pour mettre à jour les tableaux et les arbres de segments -

int IdX, VaL; 
change(1, 0, n-1, IX, VaL, TreE);
int L, R, K; 
int count = QUERY(1, 0, M-1, L, R, K, TreE);

Algorithme

Grâce à la mise à jour, voici une manière possible de calculer le nombre. Membres du tableau supérieurs ou égaux à la valeur spécifiée -

  • Étape 1 - Créez un tableau A de taille n pour contenir la valeur de départ.

  • Étape 2 - Pour afficher une requête de plage minimale, initialisez un arbre de segments T de taille 4*n.

  • Étape 3 - Créez un arbre de segments T à l'aide de la fonction build (T, A, 1, 0, n-1), où build(T, A, v, tl, tr ) utilise les valeurs de A pour créer la plage [ tl, tr] et mettre le résultat dans le nœud v de T.

  • Étape 4 - Créez un tableau C de taille n et initialisez-le avec un nombre d'éléments supérieur ou égal au nombre spécifié.

  • Étape 5 - Créez un arbre de segments S avec une taille de départ 4*n pour représenter la somme de plage de la requête de comptage.

  • Étape 6 - Appelez la fonction build (S, C, 1, 0, n-1), où build(S, C, v, tl, tr) crée un arbre de segments de ligne S pour la plage [tl, tr], utilisez la valeur en C et conservez le résultat dans le nœud v de S.

  • Étape 7 - Répondez à chaque requête "compter les éléments supérieurs ou égaux à x" -

  • Pour trouver la valeur minimale dans la plage [l, r] du tableau A, appelez la fonction query(T, 1, 0, n-1, l, r). Supposons que le résultat soit m.

    Si m est supérieur ou égal à x, utilisez la fonction query(S, 1, 0, n-1, l, r) pour obtenir le nombre total. Nombre d'entrées dans l'intervalle [l, r] du tableau C qui sont supérieures ou égales à x. Soit le résultat c.

    Sinon, réglez c sur 0.

  • Étape 8 - "Définissez la valeur de A[i] sur v" à chaque changement de type -

  • Mettez à jour le nœud v de l'arbre de segments de ligne T dans la plage [tl,tr] et appelez la fonction update(T,v,tl,tr,i,val), où update(T,v,tl,tr,i , val) change le nœud v de l'arbre de segments T en définissant la valeur à l'index i sur val.

    Utilisez la fonction update(S, 1, 0, n-1, i, (v >= x)) pour mettre à jour le nœud de l'arborescence du segment de ligne v dans la plage [tl, tr], où update(S, v, tl , tr, i, val) met à jour le nœud v en ajoutant val au nombre d'éléments supérieurs ou égaux à x.

  • Étape 9 - Répétez à nouveau les étapes 7 et 8.

Méthode à suivre

Méthode 1

Dans l'exemple, nous définissons un vecteur de type int pour représenter notre tableau et un seuil de type int supérieur ou égal au nombre d'entrées que nous souhaitons compter. Utilisez ensuite la fonction counttheElements pour générer le tableau initial et le nombre d'éléments supérieur ou égal au seuil.

La fonction

updatetheElement accepte un tableau, l'index de l'élément à mettre à jour et la nouvelle valeur de l'élément comme paramètres et est ensuite utilisée pour mettre à jour les éléments du tableau. Enfin, nous utilisons à nouveau la méthode counttheElements pour afficher le tableau modifié et le nouveau nombre d'éléments supérieur ou égal au seuil.

Exemple 1

#include <iostream>
#include <vector>
using namespace std;
void updatethenumber(vector<int>& ara, int index, int NEWValues) {
   ara[index] = NEWValues;
}
int countthenumber(vector<int>& ara, int threshold) {
   int cont = 0;
   for (int i = 0; i < ara.size(); i++) {
      if (ara[i] >= threshold) {
         cont++;
      }
   }return cont;
}
int main () {
   vector<int> ara = {3, 6, 2,8, 4, 7} ;
   int threshold = 5;
   cout << "Initial array: ";
   for(int i = 0;i < ara.size();i++) {
      cout << ara[i] << " ";
   }cout<<endl;
   cout<<"Number of elements >= "<<threshold<< ": ";
   cout<<countthenumber(ara, threshold)<<endl;
   cout<<"Updating element at index 2 to value 9..."<<endl;
   updatethenumber(ara,2,9) ;
   cout<<"Updated array: " ;
   for(int i = 0;i<ara.size();i++) {
      cout<<ara[i]<< " ";
   } cout<<endl ;
   cout<<"Number of elements >= " << threshold << ": " ;
   cout<<countthenumber(ara, threshold)<<endl;
   return 0;
}

Sortie

Initial array: 3 6 2 8 4 7 
Number of elements >= 5: 3
Updating element at index 2 to value 9
Updated array: 3 6 9 8 4 7 
Number of elements >= 5: 4

Méthode-2

La fonction de chaque requête est de compter. Tableaux (éléments) supérieurs ou égaux à la requête [i], décrémentez toutes ces valeurs de M et exécutez le reste du problème sur le tableau mis à jour. Les entrées sont deux tableaux, array[] et query[], de tailles respectivement N et Q.

Triez d’abord le tableau[] par ordre croissant.

Recherchez l'élément dont l'élément est supérieur ou égal à query[i] en première position, tel que l.

S'il n'existe aucun élément de ce type, renvoyez 0 comme réponse. Sinon, la réponse sera N - l.

最后一步是从提供的范围内的每个元素中减去 M,并将区间 l 中的线段树更改为 N - 1。

示例 2

#include <bits/stdc++.h>
using namespace std;

void build(vector<int>& tosum, vector<int>& a, int l, int r, int rlt){
   if (l == r) {
      tosum[rlt] = a [l - 1];
      return;
   }
   int m = (l + r) >> 1;
   build (tosum, a, l, m, rlt << 1);
   build (tosum, a, m + 1, r, rlt << 1 | 1);
}
void push(vector<int>& tosum, vector<int>& toadd, int rlt, int ln, int rn){
   if (toadd[rlt]) {
      toadd [rlt<< 1] += toadd[rlt];
      toadd [rlt << 1 | 1] += toadd[rlt];
      tosum [rlt<< 1] += toadd[rlt] * ln;
      tosum [rlt << 1 | 1] += toadd[rlt] * rn;
      toadd[rlt] = 0;
   }
}
void update(vector<int>& tosum, vector<int>& toadd, int L, int R, int C, int l,int r, int rlt){
   if (L <= l && r <= R) {
      tosum[rlt] += C * (r - l + 1);
      toadd[rlt] += C;
      return;
   }
   int m = (l + r) >> 1;
   push (tosum, toadd, rlt, m - l + 1,
   r - m);
   if (L <= m)
      update (tosum, toadd, L, R, C, l, m,
      rlt << 1);
   if (R > m)
      update (tosum, toadd, L, R, C, m + 1, r,
      rlt << 1 | 1);
}
int query(vector<int>& tosum,
   vector<int>& toadd,
   int L, int R, int l,
   int r, int rlt){
   if (L <= l && r <= R) {
      return tosum[rlt];
   }
   int m = (l + r) >> 1;
   push (tosum, toadd, rlt, m - l + 1,
   r - m);
   int ans = 0;
   if (L <= m)
   ans += query (tosum, toadd, L, R, l, m,
   rlt << 1);
   if (R > m)
   ans += query (tosum, toadd, L, R, m + 1, r,
   rlt << 1 | 1);
   return ans;
}
void sequMaint(int n, int q,vector<int>& a,vector<int>& b,int m){
   sort(a.begin(), a.end());
   vector<int> tosum, toadd, ans;
   tosum.assign(n << 2, 0);
   toadd.assign(n << 2, 0);
   build (tosum, a, 1, n, 1);
   for (int i = 0; i < q; i++) {
      int l = 1, r = n, pos = -1;
      while (l <= r) {
         int m = (l + r) >> 1;
         if (query (tosum, toadd, m, m, 1, n, 1)
         >= b[i]) {
            r = m - 1;
            pos = m;
         }
         else {
            l = m + 1;
         }
      }
      if (pos == -1)
      ans.push_back(0);
      else {
         ans.push_back(n - pos + 1);
         update (tosum, toadd, pos, n, -m,
         1, n, 1);
      }
   }
   for (int i = 0; i < ans.size(); i++) {
      cout << ans[i] << " ";
   }
}
int main (){
   int A = 4;
   int B = 3;
   int C = 1;
   vector<int> array = {1, 2, 3, 4};
   vector<int> query = {4, 3, 1};
   sequMaint(A, B, array, query, C);
   return 0;
}

输出

1 2 4

结论

综上所述,线段树可以成功地用于计数。数组中大于或等于固定值并进行更新的元素的数量。我们使用惰性传播来更新线段树,而不是更新每个节点。对节点的更新是在延迟传播期间完成的,直到需要为止。总的来说,我们可以有效地数出没有。通过使用具有延迟传播的线段树,数组中大于或等于特定值且发生变化的元素。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer