牛客网暑期ACM多校训练营(第一场):J-Different Integers(分开区间不同数+树状数组)

链接:J-Different Integers

题意:给出序列a1, a2, ..., an和区间(l1, r1), (l2, r2), ..., (lq, rq),对每个区间求集合{a1, a2, ..., ai, aj, aj + 1, ..., an}中不同的数的个数。

题解:

法一:将序列数组在后面复制一遍,就形成了一个环了。这就相当于求连续区间的不同数了。

法二:离线+树状数组

   处理出每个数第一次出现的位置first、最后一次出现的位置last和所有的数的种类数tot。将区间(l, r)根据r从小到大排序。从1-n遍历离线数组,如果发现某个数a[i]最后一次出现的位置等于当前i(last[a[i]] == i),就将a[i]第一次出现的位置在树状数组中标记(add(first[a[i]])),当发现r == i时,就保存答案(tot - (sum(maxn - 1) - sum(p[k].l)))。

   原理:求出中间丢失的种类数,用总数减去即是答案。当first[a[i]] > l && last[a[i]] < r时,a[i]就不在所求集合里出现。

#include<bits/stdc++.h>
using namespace std;
 
const int maxn = 1e5 + 10;
int n, q;
int a[maxn];
int bit[maxn];
struct Node{
    int l, r, id;
    bool operator < (const Node& A) const
    {
        return r < A.r;
    }
}p[maxn];
int first[maxn], last[maxn];
int ans[maxn];
 
void add(int i)
{
    while(i > 0 && i < maxn){
        bit[i]++;
        i += i & -i;
    }
}
 
int sum(int i)
{
    int ans = 0;
    while(i){
        ans += bit[i];
        i -= i & -i;
    }
    return ans;
}
 
int main()
{
    while(scanf("%d%d", &n, &q) != EOF){
 
        memset(bit, 0, sizeof(bit));
        
        memset(first, -1, sizeof(first));
        memset(last, -1, sizeof(last));
        int tot = 0;
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
            last[a[i]] = i;
            if(first[a[i]] == -1){
                tot++;
                first[a[i]] = i;
            }
        }
 
        for(int i = 0; i < q; i++){
            scanf("%d%d", &p[i].l, &p[i].r);
            p[i].id = i;
        }
        sort(p, p + q);
 
        memset(ans, 0, sizeof(ans));
        for(int i = 1, k = 0; i <= n; i++){
            while(k < q && p[k].r == i){
                ans[p[k].id] = tot - (sum(maxn - 1) - sum(p[k].l));
                k++;
            }
            if(last[a[i]] == i){
                add(first[a[i]]);
            }
        }
 
        for(int i = 0; i < q; i++) printf("%d\n", ans[i]);
    }
}

 

posted @ 2018-07-20 15:19  鬼沐冢  阅读(134)  评论(0)    收藏  举报