zoukankan      html  css  js  c++  java
  • Codeforces 220B



    This problem can be solve in simpler O(NsqrtN) solution, but I will describe O(NlogN) one.

    We will solve this problem in offline. For each x (0 ≤ x < n) we should keep all the queries that end in x. Iterate that x from 0 to n - 1. Also we need to keep some array D such that for current x Dl + Dl + 1 + ... + Dx will be the answer for query [l;x]. To keep D correct, before the processing all queries that end in x, we need to update D. Let t be the current integer in A, i. e. Ax, and vector P be the list of indices of previous occurences of t (0-based numeration of vector). Then, if |P| ≥ t, you need to add 1 to DP[|P| - t], because this position is now the first (from right) that contains exactly t occurences of t. After that, if |P| > t, you need to subtract 2 from DP[|P| - t - 1], in order to close current interval and cancel previous. Finally, if |P| > t + 1, then you need additionally add 1 to DP[|P| - t - 2] to cancel previous close of the interval.

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <iostream>
    #include <iomanip>
    #include <cmath>
    #include <map>
    #include <set>
    #include <queue>
    using namespace std;
    
    #define ls(rt) rt*2
    #define rs(rt) rt*2+1
    #define ll long long
    #define ull unsigned long long
    #define rep(i,s,e) for(int i=s;i<e;i++)
    #define repe(i,s,e) for(int i=s;i<=e;i++)
    #define CL(a,b) memset(a,b,sizeof(a))
    #define IN(s) freopen(s,"r",stdin)
    #define OUT(s) freopen(s,"w",stdout)
    
    const int MAXN = 1e5+100;
    int n,m;
    
    int a[MAXN],c[MAXN],ans[MAXN];
    struct Query
    {
        int l,r,id;
        bool operator < (const Query &t) const {return r<t.r;}
    }q[MAXN];
    inline int lowbit(int x){return x&(-x);}
    void add(int i, int v)
    {
        while(i<=n)
        {
            c[i]+=v;
            i+=lowbit(i);
        }
    }
    int sum(int x)
    {
        int ret=0;
        while(x>0)
        {
            ret+=c[x];
            x-=lowbit(x);
        }
        return ret;
    }
    
    int main()
    {
        int sz;
        while(~scanf("%d%d",&n,&m))
        {
            vector<int>data[MAXN];
            CL(c,0);
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&q[i].l,&q[i].r);
                q[i].id=i;
            }
            sort(q+1,q+1+m);
            for(int i=1,k=1;i<=n;i++)
            {
                if(a[i]<=n)
                {
                    data[a[i]].push_back(i);
                    sz=data[a[i]].size();
                    if(sz>=a[i])
                    {
                        add(data[a[i]][sz-a[i]],1);
                        if(sz>a[i])add(data[a[i]][sz-a[i]-1],-2);
                        if(sz>a[i]+1)add(data[a[i]][sz-a[i]-2],1);
                    }
                }
                while(q[k].r==i && k<=m)
                {
                    ans[q[k].id]=sum(q[k].r)-sum(q[k].l-1);
                    k++;
                }
            }
    
            for(int i=1;i<=m;i++)
                printf("%d
    ",ans[i]);
    
        }
        return 0;
    }
    

    用于调试理解的及及加了凝视的代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <iostream>
    #include <iomanip>
    #include <cmath>
    #include <map>
    #include <set>
    #include <queue>
    using namespace std;
    
    #define ls(rt) rt*2
    #define rs(rt) rt*2+1
    #define ll long long
    #define ull unsigned long long
    #define rep(i,s,e) for(int i=s;i<e;i++)
    #define repe(i,s,e) for(int i=s;i<=e;i++)
    #define CL(a,b) memset(a,b,sizeof(a))
    #define IN(s) freopen(s,"r",stdin)
    #define OUT(s) freopen(s,"w",stdout)
    
    const int MAXN = 1e5+100;
    int n,m;
    
    int a[MAXN],c[MAXN],ans[MAXN];
    struct Query
    {
        int l,r,id;
        bool operator < (const Query &t) const {return r<t.r;}
    }q[MAXN];
    inline int lowbit(int x){return x&(-x);}
    void add(int i, int v)
    {
        while(i<=n)
        {
            c[i]+=v;
            i+=lowbit(i);
        }
    }
    int sum(int x)
    {
        int ret=0;
        while(x>0)
        {
            ret+=c[x];
            x-=lowbit(x);
        }
        return ret;
    }
    
    int main()
    {
        int sz;
        while(~scanf("%d%d",&n,&m))
        {
            vector<int>data[MAXN];
            CL(c,0);
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&q[i].l,&q[i].r);
                q[i].id=i;
            }
            sort(q+1,q+1+m);
            for(int i=1,k=1;i<=n;i++)
            {
                if(a[i]<=n)
                {
                    data[a[i]].push_back(i);
                    sz=data[a[i]].size();
                    if(sz>=a[i])
                    {
                        add(data[a[i]][sz-a[i]],1);//从右往左第a[i]次出现a[i]的位置+1
                        if(sz>a[i])add(data[a[i]][sz-a[i]-1],-2);
                        //从右往左第a[i]+1次出现a[i]的位置 -2,
                        //由于当Sz==a[i]的时候,这个位置已经被加过1。此次读到i的时候。
                        //从右往左第a[i]次出现a[i]的位置也被+1。
                        //那么查询第a[i]+1次出现a[i]的位置到i。答案就是-2+1+1=0,
                        //查询第a[i]次出现a[i]的位置到i,答案就是1
                        if(sz>a[i]+1)add(data[a[i]][sz-a[i]-2],1);
                        //从右往左第a[i]+2次出现a[i]的位置 +1,之前被+1-2,所以变成0
                        //这三行代码维护出来,从当前的i往左数,第a[i]次出现a[i]的位置总是1
                        //第a[i]+1次出现a[i]的位置总是-1,第a[i]+2及很多其它次的位置总是0,这样以i为右端点的区间的查询结果就都对了
                    }
                }
                while(q[k].r==i && k<=m)
                {
                    /////////////
                    printf("#i=%d#
    ",i);
                    for(int j=0;j<=n;j++)
                        printf("c[%d]=%d
    ",j,c[j]);
                    //////////////
                    ans[q[k].id]=sum(q[k].r)-sum(q[k].l-1);
                    k++;
                }
            }
    
            for(int i=1;i<=m;i++)
                printf("%d
    ",ans[i]);
    
        }
        return 0;
    }
    


  • 相关阅读:
    Linux日志文件utmp、wtmp、lastlog、messages
    Linux日志五大命令详解
    php 函数合并 array_merge 与 + 的区别
    MySQL对数据表进行分组查询(GROUP BY)
    如何在mysql中查询每个分组的前几名
    Autojump:一个可以在 Linux 文件系统快速导航的高级 cd 命令
    linux 查看磁盘空间大小
    js刷新页面方法大全
    [知乎有感] 读研到底为了什么,值不值得?
    [Hadoop] 在Ubuntu系统上一步步搭建Hadoop(单机模式)
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5266774.html
Copyright © 2011-2022 走看看