zoukankan      html  css  js  c++  java
  • [Ahoi2013]作业

    此时己是凌晨两点,刚刚做了Codeforces的小A掏出了英语试卷。英语作业其实不算多,一个小时刚好可以做完。然后是一个小时可以做完的数学作业,接下来是分别都是一个小时可以做完的化学,物理,语文......小A压力巨大。

    这是小A碰见了一道非常恶心的数学题,给定了一个长度为n的数列和若干个询问,每个询问是关于数列的区间表示数列的第1个数到第r个数),首先你要统计该区间内大于等于a,小于等于b的数的个数,其次是所有大于等于a,小于等于b的,且在该区间中出现过的数值的个数。

    小A望着那数万的数据规模几乎绝望,只能向大神您求救,请您帮帮他吧。

    输入输出格式
    输入格式:

    第一行n,m

    接下来n个数表示数列

    接下来m行,每行四个数l,r,a,b
    N<=100000,M<=100000

    输出格式:

    输出m行,分别对应每个询问,输出两个数,分别为在1到i?这段区间中大小在[a,b]中的数的个数,以及大于等于a,小于等于b的,且在该区间中出现过的数值的个数(具体可以参考样例)。

    输入输出样例
    输入样例#1:

    3 4

    1 2 2

    1 2 1 3

    1 2 1 1

    1 3 1 3

    2 3 2 3

    输出样例#1:
    2 2
    1 1
    3 2
    2 1

    Sol:莫队加树状数组

    /*
    莫队+树状数组
    用莫队解决[l,r]的问题
    两个树状数组,以权值为下标,一个记录权值为i的是否出现,
    一个记录权值为i的出现了几次
    */
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define N 100001
    using namespace std;
    int n,m,size,l=1,r,tmp;
    int key[N],sum[N],c[2][N];
    int ans[N*10][2];
    struct node
    {
        int l,r,a,b;
        int bl,id;
        int ans1,ans2;
    }e[N*10];
    bool cmp(node p,node q)
    {
        if(p.bl!=q.bl) return p.bl<q.bl;
        return p.r<q.r;
    }
    int lowbit(int x)
    {
        return x&(-x);
    }
    void change(int k,int w,int h)
    //h为数组下标,为0时用于统计某个数字是否出现过
    //为1时统计数字出现的次数 
    {
        while(k<=n) { c[h][k]+=w; k+=lowbit(k);}
    }
    int query(int k,int h)
    {
        int tot=0;
        while(k) { tot+=c[h][k]; k-=lowbit(k);}
        return tot;
    }
    void update(int k,int w)
    {
        sum[key[k]]+=w; 
        change(key[k],w,1);
        if(w==1&&sum[key[k]]==1) 
    	    change(key[k],1,0);
        else 
    	      if(w==-1&&!sum[key[k]]) 
    		      change(key[k],-1,0);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        size=sqrt(n);
        for(int i=1;i<=n;i++) 
    	    scanf("%d",&key[i]);
        for(int i=1;i<=m;i++) 
        {
            scanf("%d%d%d%d",&e[i].l,&e[i].r,&e[i].a,&e[i].b);
            e[i].bl=(e[i].l-1)/size+1;
            e[i].id=i;
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=m;i++)
        {
            while(e[i].l<l) update(--l,1);
            while(e[i].l>l) update(l++,-1);
            while(e[i].r<r) update(r--,-1);
            while(e[i].r>r) update(++r,1);
            e[i].ans1=query(e[i].b,0)-query(e[i].a-1,0);
            e[i].ans2=query(e[i].b,1)-query(e[i].a-1,1);
        }
        for(int i=1;i<=m;i++) 
    	ans[e[i].id][0]=e[i].ans2 , 
    	//出现了多少个数字在规定范围内 
    	ans[e[i].id][1]=e[i].ans1;
    	//出现了多少种数字在规定范围内 
        for(int i=1;i<=m;i++) 
    	printf("%d %d
    ",ans[i][0],ans[i][1]);
    	
    }
    

      

  • 相关阅读:
    第十一单元 beego验证
    第九单元 ORM
    第六单元 go操作redis
    第五单元 go操作mysql
    第四单元 参数配置
    springboot使用外置tomcat
    ⚡ 第二.三章顺序表与链表⚡
    c语言程序设计题 译密码
    翁恺 java进阶第一周作业
    Java 构造素数表的两种方法
  • 原文地址:https://www.cnblogs.com/cutemush/p/12865093.html
Copyright © 2011-2022 走看看