📌  相关文章
📜  查找范围内不同数字的计数

📅  最后修改于: 2021-09-16 11:06:39             🧑  作者: Mango

给定一个大小为 N 的数组,只包含从 0 到 63 的数字,你会被问到 Q 个关于它的查询。

查询如下:

  • 1 XY 即将索引 X 处的元素更改为 Y
  • 2 LR 即打印 L 和 R 之间存在的不同元素的计数

例子:

Input:
N = 7
ar = {1, 2, 1, 3, 1, 2, 1}
Q = 5
{ {2, 1, 4},
  {1, 4, 2},
  {1, 5, 2},
  {2, 4, 6},
  {2, 1, 7} }
Output:
3
1
2

Input:
N = 15
ar = {4, 6, 3, 2, 2, 3, 6, 5, 5, 5, 4, 2, 1, 5, 1}
Q = 5
{ {1, 6, 5},
  {1, 4, 2},
  {2, 6, 14},
  {2, 6, 8},
  {2, 1, 6} };

Output:
5
2
5

先决条件:段树和位操作
方法:

  • 问题中形成的位掩码将表示第 i 个数字的存在与否,我们将通过检查我们的位掩码的第 i 位发现,如果第 i 位打开,则表示存在第 i 个元素,否则不存在。
  • 构建一个经典的段树,它的每个节点将包含一个位掩码,用于解码由特定节点定义的特定段中不同元素的数量。
  • 以自底向上的方式构建segment Tree,因此可以通过对该节点的左右子节点的bitMask进行按位或运算,轻松计算出当前segment树节点的bitMask。叶节点将单独处理。更新也将以相同的方式进行。

下面是上述方法的实现:

C++
// C++ Program to find the distinct
// elements in a range
#include 
using namespace std;
  
// Function to perform queries in a range
long long query(int start, int end, int left, int right,
                int node, long long seg[])
{
    // No overlap
    if (end < left || start > right) {
        return 0;
    }
  
    // Totally Overlap
    else if (start >= left && end <= right) {
        return seg[node];
    }
  
    // Parital Overlap
    else {
        int mid = (start + end) / 2;
  
        // Finding the Answer
        // for the left Child
        long long leftChild = query(start, mid, left,
                                    right, 2 * node, seg);
  
        // Finding the Answer
        // for the right Child
        long long rightChild = query(mid + 1, end, left,
                                     right, 2 * node + 1, seg);
  
        // Combining the BitMasks
        return (leftChild | rightChild);
    }
}
  
// Function to perform update operation
// in the Segment seg
void update(int left, int right, int index, int Value,
            int node, int ar[], long long seg[])
{
    if (left == right) {
        ar[index] = Value;
  
        // Forming the BitMask
        seg[node] = (1LL << Value);
        return;
    }
  
    int mid = (left + right) / 2;
    if (index > mid) {
  
        // Updating the left Child
        update(mid + 1, right, index, Value, 2 * node + 1, ar, seg);
    }
    else {
  
        // Updating the right Child
        update(left, mid, index, Value, 2 * node, ar, seg);
    }
  
    // Updating the BitMask
    seg[node] = (seg[2 * node] | seg[2 * node + 1]);
}
  
// Building the Segment Tree
void build(int left, int right, int node, int ar[],
           long long seg[])
{
    if (left == right) {
  
        // Building the Initial BitMask
        seg[node] = (1LL << ar[left]);
  
        return;
    }
  
    int mid = (left + right) / 2;
  
    // Building the left seg tree
    build(left, mid, 2 * node, ar, seg);
  
    // Building the right seg tree
    build(mid + 1, right, 2 * node + 1, ar, seg);
  
    // Forming the BitMask
    seg[node] = (seg[2 * node] | seg[2 * node + 1]);
}
  
// Utility Function to answer the queries
void getDistinctCount(vector >& queries,
                      int ar[], long long seg[], int n)
{
  
    for (int i = 0; i < queries.size(); i++) {
  
        int op = queries[i][0];
  
        if (op == 2) {
  
            int l = queries[i][1], r = queries[i][2];
  
            long long tempMask = query(0, n - 1, l - 1,
                                       r - 1, 1, seg);
  
            int countOfBits = 0;
  
            // Counting the set bits which denote the
            // distinct elements
            for (int i = 63; i >= 0; i--) {
  
                if (tempMask & (1LL << i)) {
  
                    countOfBits++;
                }
            }
  
            cout << countOfBits << '\n';
        }
        else {
  
            int index = queries[i][1];
            int val = queries[i][2];
  
            // Updating the value
            update(0, n - 1, index - 1, val, 1, ar, seg);
        }
    }
}
  
// Driver Code
int main()
{
    int n = 7;
    int ar[] = { 1, 2, 1, 3, 1, 2, 1 };
  
    long long seg[4 * n] = { 0 };
    build(0, n - 1, 1, ar, seg);
  
    int q = 5;
    vector > queries = {
        { 2, 1, 4 },
        { 1, 4, 2 },
        { 1, 5, 2 },
        { 2, 4, 6 },
        { 2, 1, 7 }
    };
  
    getDistinctCount(queries, ar, seg, n);
  
    return 0;
}


Java
// Java Program to find the distinct
// elements in a range
import java.util.*;
  
class GFG{
   
// Function to perform queries in a range
static long query(int start, int end, int left, int right,
                int node, long seg[])
{
    // No overlap
    if (end < left || start > right) {
        return 0;
    }
   
    // Totally Overlap
    else if (start >= left && end <= right) {
        return seg[node];
    }
   
    // Parital Overlap
    else {
        int mid = (start + end) / 2;
   
        // Finding the Answer
        // for the left Child
        long leftChild = query(start, mid, left,
                                    right, 2 * node, seg);
   
        // Finding the Answer
        // for the right Child
        long rightChild = query(mid + 1, end, left,
                                     right, 2 * node + 1, seg);
   
        // Combining the BitMasks
        return (leftChild | rightChild);
    }
}
   
// Function to perform update operation
// in the Segment seg
static void update(int left, int right, int index, int Value,
            int node, int ar[], long seg[])
{
    if (left == right) {
        ar[index] = Value;
   
        // Forming the BitMask
        seg[node] = (1L << Value);
        return;
    }
   
    int mid = (left + right) / 2;
    if (index > mid) {
   
        // Updating the left Child
        update(mid + 1, right, index, Value, 2 * node + 1, ar, seg);
    }
    else {
   
        // Updating the right Child
        update(left, mid, index, Value, 2 * node, ar, seg);
    }
   
    // Updating the BitMask
    seg[node] = (seg[2 * node] | seg[2 * node + 1]);
}
   
// Building the Segment Tree
static void build(int left, int right, int node, int ar[],
           long seg[])
{
    if (left == right) {
   
        // Building the Initial BitMask
        seg[node] = (1L << ar[left]);
   
        return;
    }
   
    int mid = (left + right) / 2;
   
    // Building the left seg tree
    build(left, mid, 2 * node, ar, seg);
   
    // Building the right seg tree
    build(mid + 1, right, 2 * node + 1, ar, seg);
   
    // Forming the BitMask
    seg[node] = (seg[2 * node] | seg[2 * node + 1]);
}
   
// Utility Function to answer the queries
static void getDistinctCount(int  [][]queries,
                      int ar[], long seg[], int n)
{
   
    for (int i = 0; i < queries.length; i++) {
   
        int op = queries[i][0];
   
        if (op == 2) {
   
            int l = queries[i][1], r = queries[i][2];
   
            long tempMask = query(0, n - 1, l - 1,
                                       r - 1, 1, seg);
   
            int countOfBits = 0;
   
            // Counting the set bits which denote the
            // distinct elements
            for (int s = 63; s >= 0; s--) {
   
                if ((tempMask & (1L << s))>0) {
   
                    countOfBits++;
                }
            }
   
            System.out.println(countOfBits);
        }
        else {
   
            int index = queries[i][1];
            int val = queries[i][2];
   
            // Updating the value
            update(0, n - 1, index - 1, val, 1, ar, seg);
        }
    }
}
   
// Driver Code
public static void main(String[] args)
{
    int n = 7;
    int ar[] = { 1, 2, 1, 3, 1, 2, 1 };
   
    long seg[] = new long[4 * n];
    build(0, n - 1, 1, ar, seg);
   
    int [][]queries = {
        { 2, 1, 4 },
        { 1, 4, 2 },
        { 1, 5, 2 },
        { 2, 4, 6 },
        { 2, 1, 7 }
    };
   
    getDistinctCount(queries, ar, seg, n);
   
}
}
  
// This code is contributed by PrinciRaj1992


Python3
# Python3 Program to find the distinct
# elements in a range
  
# Function to perform queries in a range
def query(start, end, left, 
          right, node, seg):
      
    # No overlap
    if (end < left or start > right):
        return 0
  
    # Totally Overlap
    elif (start >= left and 
            end <= right):
        return seg[node]
  
    # Parital Overlap
    else:
        mid = (start + end) // 2
  
        # Finding the Answer
        # for the left Child
        leftChild = query(start, mid, left, 
                          right, 2 * node, seg)
  
        # Finding the Answer
        # for the right Child
        rightChild = query(mid + 1, end, left,
                           right, 2 * node + 1, seg)
  
        # Combining the BitMasks
        return (leftChild | rightChild)
  
# Function to perform update operation
# in the Segment seg
def update(left, right, index, 
           Value, node, ar, seg):
    if (left == right):
        ar[index] = Value
  
        # Forming the BitMask
        seg[node] = (1 << Value)
        return
  
    mid = (left + right) // 2
    if (index > mid):
  
        # Updating the left Child
        update(mid + 1, right, index, 
               Value, 2 * node + 1, ar, seg)
    else:
  
        # Updating the right Child
        update(left, mid, index,
               Value, 2 * node, ar, seg)
  
    # Updating the BitMask
    seg[node] = (seg[2 * node] | 
                 seg[2 * node + 1])
  
# Building the Segment Tree
def build(left, right, node, ar, eg):
  
    if (left == right):
  
        # Building the Initial BitMask
        seg[node] = (1 << ar[left])
  
        return
  
    mid = (left + right) // 2
  
    # Building the left seg tree
    build(left, mid, 2 * node, ar, seg)
  
    # Building the right seg tree
    build(mid + 1, right, 
                2 * node + 1, ar, seg)
  
    # Forming the BitMask
    seg[node] = (seg[2 * node] | 
                 seg[2 * node + 1])
  
# Utility Function to answer the queries
def getDistinctCount(queries, ar, seg, n):
  
    for i in range(len(queries)):
  
        op = queries[i][0]
  
        if (op == 2):
  
            l = queries[i][1]
            r = queries[i][2]
  
            tempMask = query(0, n - 1, l - 1,
                             r - 1, 1, seg)
  
            countOfBits = 0
  
            # Counting the set bits which denote 
            # the distinct elements
            for i in range(63, -1, -1):
  
                if (tempMask & (1 << i)):
  
                    countOfBits += 1
  
            print(countOfBits)
        else:
  
            index = queries[i][1]
            val = queries[i][2]
  
            # Updating the value
            update(0, n - 1, index - 1, 
                       val, 1, ar, seg)
  
# Driver Code
if __name__ == '__main__':
    n = 7
    ar = [1, 2, 1, 3, 1, 2, 1]
  
    seg = [0] * 4 * n
    build(0, n - 1, 1, ar, seg)
  
    q = 5
    queries = [[ 2, 1, 4 ],
               [ 1, 4, 2 ],
               [ 1, 5, 2 ],
               [ 2, 4, 6 ],
               [ 2, 1, 7 ]]
  
    getDistinctCount(queries, ar, seg, n)
  
# This code is contributed by Mohit Kumar


C#
// C# Program to find the distinct
// elements in a range
using System;
  
class GFG{
    
// Function to perform queries in a range
static long query(int start, int end, int left, int right,
                int node, long []seg)
{
    // No overlap
    if (end < left || start > right) {
        return 0;
    }
    
    // Totally Overlap
    else if (start >= left && end <= right) {
        return seg[node];
    }
    
    // Parital Overlap
    else {
        int mid = (start + end) / 2;
    
        // Finding the Answer
        // for the left Child
        long leftChild = query(start, mid, left,
                                    right, 2 * node, seg);
    
        // Finding the Answer
        // for the right Child
        long rightChild = query(mid + 1, end, left,
                                     right, 2 * node + 1, seg);
    
        // Combining the BitMasks
        return (leftChild | rightChild);
    }
}
    
// Function to perform update operation
// in the Segment seg
static void update(int left, int right, int index, int Value,
            int node, int []ar, long []seg)
{
    if (left == right) {
        ar[index] = Value;
    
        // Forming the BitMask
        seg[node] = (1L << Value);
        return;
    }
    
    int mid = (left + right) / 2;
    if (index > mid) {
    
        // Updating the left Child
        update(mid + 1, right, index, Value, 2 * node + 1, ar, seg);
    }
    else {
    
        // Updating the right Child
        update(left, mid, index, Value, 2 * node, ar, seg);
    }
    
    // Updating the BitMask
    seg[node] = (seg[2 * node] | seg[2 * node + 1]);
}
    
// Building the Segment Tree
static void build(int left, int right, int node, int []ar,
           long []seg)
{
    if (left == right) {
    
        // Building the Initial BitMask
        seg[node] = (1L << ar[left]);
    
        return;
    }
    
    int mid = (left + right) / 2;
    
    // Building the left seg tree
    build(left, mid, 2 * node, ar, seg);
    
    // Building the right seg tree
    build(mid + 1, right, 2 * node + 1, ar, seg);
    
    // Forming the BitMask
    seg[node] = (seg[2 * node] | seg[2 * node + 1]);
}
    
// Utility Function to answer the queries
static void getDistinctCount(int  [,]queries,
                      int []ar, long []seg, int n)
{
    
    for (int i = 0; i < queries.GetLength(0); i++) {
    
        int op = queries[i,0];
    
        if (op == 2) {
    
            int l = queries[i,1], r = queries[i,2];
    
            long tempMask = query(0, n - 1, l - 1,
                                       r - 1, 1, seg);
    
            int countOfBits = 0;
    
            // Counting the set bits which denote the
            // distinct elements
            for (int s = 63; s >= 0; s--) {
    
                if ((tempMask & (1L << s))>0) {
    
                    countOfBits++;
                }
            }
    
            Console.WriteLine(countOfBits);
        }
        else {
    
            int index = queries[i,1];
            int val = queries[i,2];
    
            // Updating the value
            update(0, n - 1, index - 1, val, 1, ar, seg);
        }
    }
}
    
// Driver Code
public static void Main(String[] args)
{
    int n = 7;
    int []ar = { 1, 2, 1, 3, 1, 2, 1 };
    
    long []seg = new long[4 * n];
    build(0, n - 1, 1, ar, seg);
    
    int [,]queries = {
        { 2, 1, 4 },
        { 1, 4, 2 },
        { 1, 5, 2 },
        { 2, 4, 6 },
        { 2, 1, 7 }
    };
    
    getDistinctCount(queries, ar, seg, n);
    
}
}
  
// This code is contributed by 29AjayKumar


输出:
3
1
2

时间复杂度: O(N + Q*Log(N))