zoukankan      html  css  js  c++  java
  • SDOI2009 HH的项链

    传送门

    这道题原来是可以用莫队暴力过掉的……但是数据加强之后500000万的范围使得nsqrtn的算法无法通过,那我们只能用log的方法,也就是树状数组。

    本题要求我们统计的是贝壳的个数,我们唯一的困难在于如何判断重复元素。考虑这样一个事情,对于一些右端点相同的区间,我们在统计这些区间之内的情况的时候,重复的元素我们只关心它出现在最右边的一个。

    举例子,比如区间1,2,3,2,4 对于这个长度为5的区间,我们对于每个诸如[l,5]的询问,第一个2完全不需要被考虑,因为它已经被第二个2完全覆盖了。(左端点靠前的,2可以被后面的计算,靠后的就完全没前面事了

    所以我们可以把所有的区间按右端点排序,之后离线处理。对于每个右端点,把在其之前的都在树状数组中加上,而已经出现过的元素,就在原来的位置先删除,之后再在当前位置添加。统计的时候直接计算两端和相减即可。

    听起来是不是很简单……?

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    const int M = 1005;
    const int N = 1000005;
    const int INF = 1e9;
    double eps = 1e-7;
    typedef long long ll;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    struct ask
    {
        int l,r,pos;
        bool operator < (const ask &g) const
        {
            if(r == g.r) return l < g.l;
            return r < g.r;
        }
    }a[N];
    struct answer
    {
        int val,p;
        bool operator < (const answer &g) const
        {
            return p < g.p;
        }
    }ans[N];
    int n,m,shell[N],cur = 1,c[N],loc[N];
    bool vis[N];
    int lowbit(int x)
    {
        return x & (-x);
    }
    void add(int x,int v)
    {
        while(x <= n)
        {    
            c[x] += v;
            x += lowbit(x);
        }
    }
    int query(int x)
    {
        int sum = 0;
        while(x)
        {
            sum += c[x];
            x -= lowbit(x);
        }
        return sum;
    }
    int main()
    {
        n = read();
        rep(i,1,n) shell[i] = read();
        m = read();
        rep(i,1,m) a[i].l = read(),a[i].r = read(),a[i].pos = i;
        sort(a+1,a+1+m);
        rep(i,1,m)
        {
            while(cur <= a[i].r)//所有在前面的都要统计
            {
                if(!vis[shell[cur]]) add(cur,1),loc[shell[cur]] = cur,vis[shell[cur]] = 1;//这个元素没出现过
                else add(loc[shell[cur]],-1),add(cur,1),loc[shell[cur]] = cur;//元素出现过
                cur++;
            }
            ans[i].val = query(a[i].r) - query(a[i].l-1),ans[i].p = a[i].pos;//计算出现次数
        }
        sort(ans+1,ans+1+m);//注意要重新按照出现的次序排序
        rep(i,1,m) printf("%d
    ",ans[i].val);
        return 0;
    }
  • 相关阅读:
    PAT (Advanced Level) Practice 1071 Speech Patterns (25分)
    PAT (Advanced Level) Practice 1070 Mooncake (25分)
    PAT (Advanced Level) Practice 1069 The Black Hole of Numbers (20分)
    PAT (Advanced Level) Practice 1074 Reversing Linked List (25分)
    PAT (Advanced Level) Practice 1073 Scientific Notation (20分)
    第一次冲刺个人总结01
    构建之法阅读笔记01
    人月神话阅读笔记01
    四则运算2
    学习进度条(软件工程概论1-8周)
  • 原文地址:https://www.cnblogs.com/captain1/p/9571899.html
Copyright © 2011-2022 走看看