zoukankan      html  css  js  c++  java
  • 牛客暑假多校第一场J-Different Integers

    一、题目描述:

    链接:https://www.nowcoder.com/acm/contest/139/J
    Given a sequence of integers a1, a2, ..., an and q pairs of integers (l1, r1), (l2, r2), ..., (lq, rq), find count(l1, r1), count(l2, r2), ..., count(lq, rq) where count(i, j) is the number of different integers among a1, a2, ..., ai, aj, aj + 1, ..., an.

    大概是说,给一个长为n的数组,要求进行m次查询,每次给出l,r要求统计数组内,除了(l,r)区间内的其他元素的种类数。

    二、思路

    考虑一个元素有两个属性:第一次出现的地方和最后一次出现的地方:记为first[x]和last[x]

    则答案应为,总元素个数 - 只在给定区间内出现的元素个数。

    则问题实际上转化为 求count(first[x],last[x] ∈ (l,r))。

    考虑实际上对于每个元素来说,first[x],和last[x]可以理解为二元组——或者二维空间的坐标,则问题实际转化为二维空间内的点统计问题。因为元素太多,所以考虑使用主席树的方式来构造二维线段树。

    但是进一步观察可得,每一行每一列都只有一个元素可能存在。于是如果保证二元组(first[x],last[x])中last[x]保持递增顺序其实就没必要一定要构造主席树来进行数字统计——直接用树状数组挂vector之后用lower_bound查出现位置即可。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define pp pair<int,int>
    #define veci vector<int>
    #define vecp vector<pp>
    
    const int MAXN=100233;
    vecp p;
    
    int first[MAXN];
    int last[MAXN];
    int arr[MAXN];
    int n,m;
    
    int summ ;
    
    class Node
    {
        public:
            veci arr;
    };
    Node arr_1[MAXN];
    
    void insert(int a,int b)
    {
        // cout<<a<<" "<<b<<endl;
        a += 10;
        while(a<n+23)
        {
            arr_1[a].arr.push_back(b);
            a += a &(-a);
        }
    }
    
    int count(int a,int b)
    {
        // cout<<"query: "<<a<<" "<<b<<endl;
        a += 10;
        int cnt = 0;
       
        while(a)
        {
            int tmp = lower_bound(arr_1[a].arr.begin(),arr_1[a].arr.end(),b)-arr_1[a].arr.begin();
            // if(tmp != arr_1[a].arr.size() && arr_1[a].arr[tmp] == b)tmp ++;
            cnt += tmp;
     
                // cout<< "tmp: "<<tmp<<" size"<<arr_1[a].arr.size()<<endl;  
            a-=a&(-a);
        }
        return cnt;
    }
    
    
    
    bool cmp(pp p1,pp p2)
    {
        return p1.second<p2.second;
    }
    
    void init()
    {
        summ = 0;
        memset(first,-1,sizeof(first));
        memset(last,-1,sizeof(last));
        p.clear();
        for(int i=0;i<n;++i)scanf("%d",&arr[i]);//cin>>arr[i];
        for(int i=0;i<n+23;++i)arr_1[i].arr.clear();
        for(int i=0;i<n;++i)
        {
            int a = i;
            int b = n-1-i;
            int ta = arr[a];
            int tb = arr[b];
            if(first[ta] == -1)
            {
                summ++;
                first[ta] = a;
                if(last[ta] != -1)
                    p.push_back(make_pair(first[ta],last[ta]));
            }
            if(last[tb] == -1)
            {
                last[tb] = b;
                if(first[tb]!= -1)
                    p.push_back(make_pair(first[tb],last[tb]));
            }
        }
        sort(p.begin(),p.end(),cmp);
        int len = p.size();
        for(int i=0;i<len;++i)
        {
            insert(p[i].first,p[i].second);
        }
        for(int i=0;i<m;++i)
        {
            int a,b;
            // cin>>a>>b;
            scanf("%d%d",&a,&b);
            a--;b--;
            cout<<summ-(count(b-1,b) - count(a,b))<<"
    ";
        }
    
    }
    
    int main()
    {
    
        while(cin>>n>>m)init();
    
        return 0;
    }
  • 相关阅读:
    .net framework缓存遍历
    R语言中统计数据框所有项中的并集
    R语言中在数据框中批量替换指定项
    R语言中 %in%用法
    windows中如何查看端口占用情况、端口是否开启
    R语言中rbind函数和cbind的用法
    linux系统shell实现统计 plink文件基因频率
    linux 系统中实现列转行 及 行转列
    linux系统中向行末添加换行符
    R语言中实现方差和标准差
  • 原文地址:https://www.cnblogs.com/rikka/p/9341355.html
Copyright © 2011-2022 走看看