簡體   English   中英

用於添加和查找查詢的適當數據結構

[英]Appropriate data structure for add and find queries

我有兩種類型的查詢。

1 XY

在集合中添加元素 X,Y 次。

2 牛

查詢次數 < 5 * 10^5

X < 10^9

Y < 10^9

在已排序的集合中查找第 N 個元素。

我嘗試了 STL 設置,但沒有成功。

我認為我們需要平衡樹,每個節點都包含兩個數據值。

第一個值將是元素 X。另一個將是小於或等於值的元素的所有 Y 的前綴總和。

當我們添加元素 X 時,找到第一個值的預處理器。將與預處理器關聯的第二個值添加到 Y。

當找到第 N 個元素時。 在樹(第二個值)中搜索立即低於 N 的值。

如何高效地實現這種數據結構?

這可以使用復雜度為 O(Q*log(10^9)) 的分段樹數據結構輕松完成

  1. 我們應該使用所謂的“稀疏”分段樹,以便我們只在需要時創建節點,而不是創建所有節點。
  2. 在每個節點中,我們將保存 [L, R] 范圍內的元素計數
  3. 現在,通過從根到葉遍歷段樹並更新值(也創建尚不存在的節點),可以輕松地添加一些元素 y 次。 由於段樹的高度是對數的,這需要 log N 時間,其中 N 是我們的初始間隔長度 (10^9)
  4. 使用分段樹上的二分查找可以輕松找到第 k 個元素,因為在每個節點上我們都知道某個范圍內元素的計數,我們可以使用此信息向左或向右遍歷包含第 k 個元素的元素

示例代碼(C++):

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

const int sz = 31*4*5*100000;
ll seg[sz];
int L[sz],R[sz];
int nxt = 2;

void IncNode(int c, int l, int r, int idx, int val)
{
    if(l==r)
    {
        seg[c]+=val;
        return;
    }

    int m = (l+r)/2;

    if(idx <= m)
    {
        if(!L[c])L[c]=nxt++;
        IncNode(L[c],l,m,idx,val);
    }
    else
    {
        if(!R[c])R[c]=nxt++;
        IncNode(R[c],m+1,r,idx,val);
    }

    seg[c] = seg[L[c]] + seg[R[c]];
}

int FindKth(int c, int l, int r, ll k)
{
    if(l==r)return r;

    int m = (l+r)/2;

    if(seg[L[c]] >= k)return FindKth(L[c],l,m,k);
    return FindKth(R[c],m+1,r,k-seg[L[c]]);
}

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int Q;
    cin>>Q;
    int L = 0, R = 1e9;

    while(Q--)
    {
        int type;
        cin>>type;

        if(type==1)
        {
            int x,y;
            cin>>x>>y;
            IncNode(1,L,R,x,y);
        }
        else
        {
            int k;
            cin>>k;
            cout<<FindKth(1,L,R,k)<<"\n";
        }
    }
}

在每個節點中維護前綴和是不切實際的。 這意味着每次添加新節點時,都必須更新樹中每個節點的前綴和。 相反,您需要維護子樹總和:每個節點應包含其自己的鍵和所有后代的鍵的 Y 值的總和。 更新樹時維護子樹總和應該很簡單。

當您回答類型 2 的查詢時,在每個節點上,如果 N 小於或等於左孩子的子樹總和值 S(我假設 N 是 1 索引),您將下降到左子樹。 否則,從 N 中減去 S + 1 並下降到右子樹。

順便說一句,如果事先知道整個 X 值集,那么您可以使用范圍樹或二叉索引樹來代替平衡 BST。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM