首页 > 其他分享 >abc174F Range Set Query

abc174F Range Set Query

时间:2024-10-09 19:48:56浏览次数:9  
标签:node Set const int abc174F son Range ans data

给定数组A[N],有Q个询问,每个询问给出l[i]和r[i],问区间[l[i],r[i]]内有多少个不同的数?
1<=N,Q<=5E5; 1<=A[i]<=N; 1<=l[i]<=r[i]<=N

分析:对询问按右端点从小到大排序,然后从左到右依次处理每个A[i],将下标i的位置置为1,如果前面出现过A[i],则把上一次出现的位置置为0,然后处理右端点为i的询问,其实就是个前缀和问题,可以用BIT来维护,这里用的平衡树。

#include <bits/stdc++.h>
using i64 = long long;

template <typename TYPE>
struct Treap {
    struct Node {
        TYPE data;
        int rnd, siz, dup, son[2];
        Node() { memset(&data, 0, sizeof(data)); rnd = siz = son[0] = son[1] = 0; }
        Node(const TYPE &d, int cnt=1) { init(d, cnt); }
        void init(const TYPE & d, int cnt) { data = d; dup = siz = cnt; rnd = rand(); son[0] = son[1] = 0; }
    };
    Treap(int multi=1):multiple(multi) { reset(); }
    void setmulti(int multi) { multiple = multi; }
    int newnode(const TYPE & d, int cnt) {
        if (!reuse.empty()) {
            int r = reuse.front();
            reuse.pop_front();
            node[r].init(d, cnt);
            return r;
        }
        node.push_back({d, cnt});
        return node.size() - 1;
    }
    void reset() { root = 0; node.resize(1); reuse.clear(); }
    void maintain(int x) {
        node[x].siz = node[x].dup;
        if (node[x].son[0]) {
            node[x].siz += node[node[x].son[0]].siz;
        }
        if (node[x].son[1]) {
            node[x].siz += node[node[x].son[1]].siz;
        }
    }
    void rotate(int d, int &r) {
        int k = node[r].son[d^1];
        node[r].son[d^1] = node[k].son[d];
        node[k].son[d] = r;
        maintain(r);
        maintain(k);
        r = k;
    }
    void insert(const TYPE &data, int cnt, int &r) {
        if (r) {
            if (!(data < node[r].data) && !(node[r].data < data)) {
                if (multiple) {
                    node[r].dup += cnt;
                    maintain(r);
                }
            } else {
                int d = data < node[r].data ? 0 : 1;
                // avoid push_back -> realloc
                int u = node[r].son[d];
                insert(data, cnt, u);
                node[r].son[d] = u;
                if (node[node[r].son[d]].rnd > node[r].rnd) {
                    rotate(d^1, r);
                } else {
                    maintain(r);
                }
            }
        } else {
            r = newnode(data, cnt);
        }
    }
    TYPE kth(int k) {
        assert(1 <= k && k <= size());
        for (int r = root; r; ) {
            int x = node[r].son[0] ? node[node[r].son[0]].siz : 0;
            int y = node[r].dup;
            if (k <= x) {
                r = node[r].son[0];
            } else if (k <= x + y) {
                return node[r].data;
            } else {
                k -= x + y;
                r = node[r].son[1];
            }
        }
        assert(k == 0);
        return 0;
    }
    TYPE Kth(int k) {
        assert(1 <= k && k <= size());
        for (int r = root; r; ) {
            int x = node[r].son[1] ? node[node[r].son[1]].siz : 0;
            int y = node[r].dup;
            if (k <= x) {
                r = node[r].son[1];
            } else if (k <= x + y) {
                return node[r].data;
            } else {
                k -= x + y;
                r = node[r].son[0];
            }
        }
        assert(k == 0);
        return 0;
    }
    void erase(const TYPE& data, int cnt, int & r) {
        if (r == 0) return;
        int d = -1;
        if (data < node[r].data) {
            d = 0;
        } else if (node[r].data < data) {
            d = 1;
        }
        if (d == -1) {
            node[r].dup -= cnt;
            if (node[r].dup > 0) {
                maintain(r);
            } else {
                if (node[r].son[0] == 0) {
                    reuse.push_back(r);
                    r = node[r].son[1];
                } else if (node[r].son[1] == 0) {
                    reuse.push_back(r);
                    r = node[r].son[0];
                } else {
                    int dd = node[node[r].son[0]].rnd > node[node[r].son[1]].rnd ? 1 : 0;
                    rotate(dd, r);
                    erase(data, cnt, node[r].son[dd]);
                }
            }
        } else {
            erase(data, cnt, node[r].son[d]);
        }
        if (r) maintain(r);
    }
    int ltcnt(const TYPE &data) {
        int ans = 0;
        for (int r = root; r; ) {
            int x = node[r].son[0] ? node[node[r].son[0]].siz : 0;
            if (node[r].data < data) {
                ans += node[r].dup + x;
                r = node[r].son[1];
            } else if (data < node[r].data) {
                r = node[r].son[0];
            } else {
                ans += x;
                break;
            }
        }
        return ans;
    }
    int gtcnt(const TYPE &data) {
        int ans = 0;
        for (int r = root; r; ) {
            int x = node[r].son[1] ? node[node[r].son[1]].siz : 0;
            if (node[r].data < data) {
                r = node[r].son[1];
            } else if (data < node[r].data) {
                ans += node[r].dup + x;
                r = node[r].son[0];
            } else {
                ans += x;
                break;
            }
        }
        return ans;
    }
    int count(const TYPE &data) {
        for (int r = root; r; ) {
            if (data < node[r].data) {
                r = node[r].son[0];
            } else if (node[r].data < data) {
                r = node[r].son[1];
            } else {
                return node[r].dup;
            }
        }
        return 0;
    }
    std::pair<bool,TYPE> prev(const TYPE &data) {
        std::pair<bool,TYPE> ans = {false, 0};
        for (int r = root; r; ) {
            if (node[r].data < data) {
                if (ans.first) {
                    ans.second = std::max(ans.second, node[r].data);
                } else {
                    ans = {true, node[r].data};
                }
                r = node[r].son[1];
            } else {
                r = node[r].son[0];
            }
        }
        return ans;
    }       
    std::pair<bool,TYPE> next(const TYPE &data) {
        std::pair<bool,TYPE> ans = {false, 0};
        for (int r = root; r; ) {
            if (data < node[r].data) {
                if (ans.first) {
                    ans.second = std::min(ans.second, node[r].data);
                } else {
                    ans = {true, node[r].data};
                }
                r = node[r].son[0];
            } else {
                r = node[r].son[1];
            }
        }
        return ans;
    }
    void dofetch(int r, std::vector<std::pair<TYPE,int>> &vec) const {
        if (r) {
            dofetch(node[r].son[0], vec);
            vec.push_back({node[r].data, node[r].dup});
            dofetch(node[r].son[1], vec);
        }
    }
    void fetch(std::vector<std::pair<TYPE,int>> &vec) const {
        dofetch(root, vec);
    }
    void merge(const Treap<TYPE> &rhs) {
        std::vector<std::pair<TYPE,int>> vp;
        rhs.fetch(vp);
        for (auto &pr : vp) {
            insert(pr.first, pr.second);
        }
    }
    std::vector<Node> node;
    std::deque<int> reuse;
    int root, multiple;
    void insert(const TYPE& data, int cnt=1) { insert(data, cnt, root); }
    void erase(const TYPE& data, int cnt=1) { erase(data, cnt, root); }
    int size() const { return root ? node[root].siz : 0; }
    int lecnt(const TYPE& data) { return size() - gtcnt(data); }
    int gecnt(const TYPE& data) { return size() - ltcnt(data); }
};

struct Node {
    int l, r, x, ans;
};

void solve() {
    int N, Q;
    std::cin >> N >> Q;
    std::vector<int> c(N + 1);
    for (int i = 1; i <= N; i++) {
        std::cin >> c[i];
    }
    std::vector<Node> qry(Q + 1);
    for (int i = 1; i <= Q; i++) {
        std::cin >> qry[i].l >> qry[i].r;
        qry[i].x = i;
    }
    std::sort(qry.begin() + 1, qry.end(), [](Node &u, Node &v){
        return u.r < v.r;
    });

    std::vector<int> lst(N + 1);
    Treap<int> tr;
    for (int i = 1, j = 1; i <= N; i++) {
        if (lst[c[i]]) {
            tr.erase(lst[c[i]]);
        }
        tr.insert(i);
        while (j <= Q && qry[j].r <= i) {
            qry[j].ans = tr.lecnt(qry[j].r) - tr.ltcnt(qry[j].l);
            j += 1;
        }
        lst[c[i]] = i;
    }

    std::sort(qry.begin() + 1, qry.end(), [](Node &u, Node &v){
        return u.x < v.x;
    });
    for (int i = 1; i <= Q; i++) {
        std::cout << qry[i].ans << "\n";
    }
}

int main() {
    std::cin.tie(0)->sync_with_stdio(0);
    std::cout << std::fixed << std::setprecision(10);
    int t = 1;
    // std::cin >> t;
    while (t--) solve();
    return 0;
}

本题也有在线做法,需要用到可持久化线段树。

标签:node,Set,const,int,abc174F,son,Range,ans,data
From: https://www.cnblogs.com/chenfy27/p/18455025

相关文章

  • java中Set的介绍与实现:HashSet、LinkedHashSet、TreeSet
    在Java中,Set是Collection接口的一个子接口,它是一个不包含重复元素的集合,且通常不保证维护元素的有序或迭代顺序。Set接口主要用于确保集合中每个元素的唯一性。Set接口的主要方法:booleanadd(Ee):将指定的元素添加到此集合中(如果它尚未在集合中)。booleanremove(Objec......
  • 《 C++ 修炼全景指南:十四 》大数据杀手锏:揭秘 C++ 中 BitSet 与 BloomFilter 的神奇性
    本篇博客深入探讨了C++中的两种重要数据结构——BitSet和BloomFilter。我们首先介绍了它们的基本概念和使用场景,然后详细分析了它们的实现方法,包括高效接口设计和性能优化策略。接着,我们通过对比这两种数据结构的性能,探讨了在不同应用场景中的选择依据。最后,博客还涵盖......
  • 在K8S中,DaemonSet类型的资源特性有哪些?
    在Kubernetes(K8s)中,DaemonSet是一种特殊的控制器资源对象,其核心特性和用途使得它非常适合用于在集群的每个节点上运行守护进程或服务。以下是DaemonSet类型的资源特性的详细阐述:1.确保每个节点上运行Pod副本节点级部署:DaemonSet确保集群中的每个节点(或满足特定条件的节点)上都运......
  • PTA JAVA语言 面向对象程序设计 作业二 6-3 Person类 构造Person类。包括姓名(name),性
    6-3Person类 谢谢大佬关注,不定期分享学习笔记,希望大佬能多多支持,三连必回单位 山东科技大学构造Person类。包括姓名(name),性别(sex)和年龄(age)。提供所有属性的set和get函数,提供print函数打印其信息输入描述:姓名(name),性别(sex)和年龄(age)输出描述:用户信息裁判测......
  • vue2 setting配置
    {  "workbench.iconTheme":"vscode-icons",  "vsicons.dontShowNewVersionMessage":true,  "terminal.integrated.profiles.windows":{    "cmd":{      "path":"C:\\Windows......
  • Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to ma
    这个错误通常发生在使用SpringAOP时,尤其是当你尝试访问AopContext.currentProxy(),但当前代理对象不可用时。下面是一些解决此问题的建议:1.启用 exposeProxy 属性确保你的AOP配置中设置了exposeProxy属性为true。这可以在使用注解或XML配置中进行设置使用注解如......
  • abc347E Set Add Query
    有数组A[N],初始时元素都为0,另外还有初始为空的集合S。依次处理以下Q组查询:给出整数x[i],如果S包含x[i],则从S中移除x[i],否则将x[i]加入S,记此时S的大小为|S|,把|S|加到集合中的每个元素i对应的A[i]中。求最终A[i]是多少。1<=N,Q<=2E5;1<=x[i]<=N分析:记录每个时刻集合S的大小,设元素u......
  • 练习题 - Scrapy爬虫框架 Settings 项目配置
    在使用Scrapy构建网络爬虫时,Settings框架配置是至关重要的部分。Settings是Scrapy框架的配置核心,它决定了爬虫的行为、请求的频率、用户代理的使用、数据存储等一系列关键功能。掌握Scrapy的配置设置,能够让你的爬虫更加高效、稳定和智能。通过合理配置,可以更好地模......
  • STL-set
    STLset头文件set主要包括set和multiset两个容器,分别是“有序集合”和“有序多重集合”即前者的元素不能重复,而后者可以包含若干个相等的元素set和multiset的内部实现是一棵红黑树,它们支持的函数基本相同include声明#include<set>函数声明set<int>s;structrec{…};......
  • ​解密 Go runtime.SetFinalizer 的使用
    解密Goruntime.SetFinalizer的使用原创 GoOfficialBlog GoOfficialBlog  2024年10月05日18:45 中国香港 听全文如果我们想在对象GC之前释放一些资源,可以使用returns.SetFinalizer。这就像在函数返回前执行 defer 来释放资源一样。例如:1:使用runtime.......