zoukankan      html  css  js  c++  java
  • 「树状数组」[SDOI2009]HH的项链

    [SDOI2009]HH的项链

    原题链接 [SDOI2009]HH的项链

    题目大意

    给你 (n) 个数,再给你 (q) 次询问,每次询问给你 (l, r) ,问你 (l, r) 中有多少个不同的数

    题目题解

    分析这道题我们发现,对于一个 ([L_1, R_1]) 存在另一个 ([L_2, R_1])(L_2) 严格大于 (L_1),那么就一定存在第一个区间不同的数 大于等于 第二个区间的不同的数,这里很显然有一种等于的情况,什么情况等于?在([L_2,R_1]) 中包含的数与 ([L_1, L_2 - 1]) 中包含的数 ,后者的数前者都有。那么我们就发现 对于这样的情况([L_1, L_2 - 1]) 中就没有必要存在了。但注意的是,这里我们是严格定义的 (R_1)相同 且(L_1 < L_2),我们继续推发现(R_2 > R_1) 也是符合条件的。

    于是我们得到若我们按查询的右区间从小到大排序,这样的就能转化为一个线性的前缀和问题,我们用数据结构来维护每一位上是否为1或0,若为1则说明之后没出现相同的数,若为1则说明出现过,每次处理到查询位的(R),然后用数据结构查询 (sum_R - sum_{l - 1}) 的值,就能得到我们的答案了

    我们这里用树状数组维护,代码如下

    //#define fre yes
    
    #include <cstdio>
    #include <algorithm>
    
    const int N = 1000005;
    struct Node {
        int l, r;
        int pos;
    } w[N];
    int Vis[N], arr[N], ans[N];
    int tree[N];
    
    bool cmp(Node x, Node y) {
        return x.r < y.r;
    }
    
    int lowbit(int x) {
        return x & (-x);
    }
    
    int n;
    void change(int x, int k) {
        while(x <= n) {
            tree[x] += k;
            x += lowbit(x);
        }
    }
    
    int sum(int x) {
        int res = 0;
        while(x > 0) {
            res += tree[x];
            x -= lowbit(x);
        } return res;
    }
    
    int main() {
        static int q;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &arr[i]);
        }
    
        scanf("%d", &q);
        for (int i = 1; i <= q; i++) {
            int l, r;
            scanf("%d %d", &l, &r);
            w[i].l = l; w[i].r = r;
            w[i].pos = i;
        }
    
        std::sort(w + 1, w + 1 + q, cmp);
    
        int tot = 1;
        for (int i = 1; i <= q; i++) {
            for (int j = tot; j <= w[i].r; j++) {
                if(Vis[arr[j]]) change(Vis[arr[j]], -1);
                change(j, 1);
                Vis[arr[j]] = j;
            }
    
            tot = w[i].r + 1;
            ans[w[i].pos] = sum(w[i].r) - sum(w[i].l - 1);
        }
    
        for (int i = 1; i <= q; i++) {
            printf("%d
    ", ans[i]);
        } return 0;
    }
    
  • 相关阅读:
    epoll使用(转)
    8、多线程小结(1)(转)
    9、多线程小结(2)(转)
    长连接和短连接(转)
    5、线程终止方式:(转)
    linux中read,write和recv,send的区别(转)
    数据访问函数库的使用方法(二)—— 获取记录集和使用事务的方法
    我想到的几句话。
    关于博克园T恤的一点想法。
    我自己写的一个分页控件(源码和演示代码)PostBack分页版 for vs2003、SQL Server
  • 原文地址:https://www.cnblogs.com/Nicoppa/p/11479310.html
Copyright © 2011-2022 走看看