Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Tanya bilangan elemen dalam tatasusunan yang lebih besar daripada atau sama dengan nombor tertentu dan kemas kininya

Tanya bilangan elemen dalam tatasusunan yang lebih besar daripada atau sama dengan nombor tertentu dan kemas kininya

王林
王林ke hadapan
2023-09-05 08:25:12914semak imbas

Tanya bilangan elemen dalam tatasusunan yang lebih besar daripada atau sama dengan nombor tertentu dan kemas kininya

Dengan bantuan pepohon segmen, tatasusunan boleh dikemas kini dengan jayanya dan pertanyaan julat dilakukan. Dengan mengemas kini, kami boleh menggunakan pepohon segmen struktur data yang diketahui untuk mengira. Bilangan elemen dalam Array lebih besar daripada atau sama dengan no.

  • Pertanyaan - Cari bilangan item yang lebih besar daripada atau serupa dengan x wujud dalam julat [l, r].

    • Diberi 0 jika julat [l, r] sepenuhnya melangkaui segmen yang diwakili oleh nod semasa pokok segmen.

    • Kira. Bilangan unsur dalam julat [l, r] yang lebih besar daripada atau serupa dengan x jika selang [l, r] terletak sepenuhnya dalam segmen yang diwakili oleh nod semasa pokok segmen.

    • Jika tidak, ping secara rekursif nod anak kiri dan kanan nod semasa, mengembalikan jumlah bilangan kiraan yang dikumpul.

  • Kemas kini - Untuk elemen di indeks i, tambahkan nilai v. Kami menggunakan algoritma berikut untuk kemas kini ini -

    • Jika julat paparan nod semasa pokok segmen tidak mempunyai indeks i, tiada operasi dilakukan.

    • Jika nilai indeks i lebih besar daripada atau sama dengan x, kemas kini kiraan elemen yang lebih besar daripada atau sama dengan x dalam selang yang diwakili oleh nod semasa pokok segmen garisan Jika nilai indeks i lebih besar daripada atau sama dengan x, naikkannya, dan kemudian kemas kini nod semasa secara rekursif Nod elemen anak kiri dan kanan.

    • Kita boleh menjalankan pertanyaan dalam julat [0, n-1] dalam nod akar pokok segmen, dengan n ialah jumlah nombor. Bilangan entri dalam tatasusunan lebih besar daripada atau sama dengan x.

Tatabahasa

1. Buat pepohon segmen dan tatasusunan dari awal -

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

2. Lakukan prosedur kemas kini (perubahan) -

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 Lakukan operasi pertanyaan berikut -

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. Gunakan operasi pertanyaan untuk mengira kuantiti. Elemen lebih besar daripada atau sama dengan nilai yang ditentukan, kemas kini operasi untuk mengemas kini tatasusunan dan pepohon segmen -

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

Algoritma

Menggunakan kemas kini, berikut adalah cara yang mungkin untuk mengira nombor. Ahli tatasusunan lebih besar daripada atau sama dengan nilai yang ditentukan -

  • Langkah 1 - Buat tatasusunan A bersaiz n untuk memegang nilai permulaan.

  • Langkah 2 - Untuk memaparkan pertanyaan julat minimum, mulakan pepohon segmen T bersaiz 4*n.

  • Langkah 3 - Buat pepohon segmen T menggunakan binaan fungsi (T, A, 1, 0, n-1), dengan bina(T, A, v, tl, tr ) menggunakan nilai dalam A untuk mencipta julat [ tl, tr], dan meletakkan hasilnya ke dalam nod v T.

  • Langkah 4 - Buat tatasusunan C bersaiz n dan mulakan dengan kiraan item yang lebih besar daripada atau sama dengan nombor yang ditentukan.

  • Langkah 5 - Buat pokok segmen S dengan saiz permulaan 4*n untuk mewakili jumlah julat pertanyaan kiraan.

  • Langkah 6 - Panggil binaan fungsi (S, C, 1, 0, n-1), dengan bina(S, C, v, tl, tr) mencipta pokok segmen garisan S untuk julat [tl, tr], Gunakan nilai dalam C dan simpan hasilnya dalam nod v S.

  • Langkah 7 - Jawab setiap pertanyaan "kira elemen lebih besar daripada atau sama dengan x" -

  • Untuk mencari nilai minimum dalam julat [l, r] tatasusunan A, panggil pertanyaan fungsi(T, 1, 0, n-1, l, r). Katakan hasilnya ialah m.

    Jika m lebih besar daripada atau sama dengan x, gunakan pertanyaan fungsi(S, 1, 0, n-1, l, r) untuk mendapatkan jumlah nombor. Bilangan entri dalam selang [l, r] tatasusunan C yang lebih besar daripada atau sama dengan x. Biarkan hasilnya c.

    Jika tidak, tetapkan c kepada 0.

  • Langkah 8 - "Tetapkan nilai A[i] kepada v" setiap perubahan jenis -

  • Kemas kini nod v pokok segmen garisan T dalam julat [tl,tr] dan panggil kemas kini fungsi(T,v,tl,tr,i,val), di mana kemas kini(T,v,tl,tr,i , val) menukar nod v pokok segmen T dengan menetapkan nilai pada indeks i kepada val.

    Gunakan kemas kini fungsi(S, 1, 0, n-1, i, (v >= x)) untuk mengemas kini nod pokok segmen baris v dalam julat [tl, tr], di mana kemas kini(S, v, tl , tr, i, val) mengemas kini nod v dengan menambah val pada kiraan item yang lebih besar daripada atau sama dengan x.

  • Langkah 9 - Ulang langkah 7 dan 8 sekali lagi.

Kaedah untuk diikuti

Kaedah 1

Dalam contoh, kami mentakrifkan vektor jenis int untuk mewakili tatasusunan kami dan ambang jenis int di atas atau sama dengan bilangan entri yang ingin kami kira. Kemudian gunakan fungsi counttheElements untuk menjana tatasusunan awal dan bilangan elemen yang lebih besar daripada atau sama dengan ambang.

Fungsi

updatetheElement menerima tatasusunan, indeks elemen yang akan dikemas kini dan nilai baharu elemen sebagai parameter dan kemudian digunakan untuk mengemas kini elemen dalam tatasusunan. Akhir sekali, kami menggunakan kaedah counttheElements sekali lagi untuk mengeluarkan tatasusunan yang diubah suai dan kiraan elemen baharu yang lebih besar daripada atau sama dengan ambang.

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

Output

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

Kaedah-2

Fungsi setiap pertanyaan adalah untuk mengira. tatasusunan (item) lebih besar daripada atau sama dengan pertanyaan[i], kurangkan semua nilai tersebut dengan M, dan jalankan baki masalah pada tatasusunan yang dikemas kini. Inputnya ialah dua tatasusunan, tatasusunan[] dan pertanyaan[], dengan saiz N dan Q masing-masing.

Isih dahulu tatasusunan[] dalam tertib menaik.

Cari elemen yang elemennya lebih besar daripada atau sama dengan pertanyaan[i] pada kedudukan pertama, seperti l.

Jika tiada elemen sedemikian, kembalikan 0 sebagai respons. Jika tidak, jawapannya ialah 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

结论

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

Atas ialah kandungan terperinci Tanya bilangan elemen dalam tatasusunan yang lebih besar daripada atau sama dengan nombor tertentu dan kemas kininya. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:tutorialspoint.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam