• 「题解」:[AHOI2013]作业


    问题: 作业

    时间限制: 10 Sec  内存限制: 512 MB

    题面


    题目描述

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

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

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

    输入格式

    第一行n,m

    接下来n个数表示数列

    接下来m行,每行四个数l,r,a,b

    输出格式

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

    题解


    这题不算太难。不过帮我复习了一下树状数组。

    一句话题解:莫队,放两个树状数组维护区间信息统计答案。

    详细部分:

    放按数据大小维护的两个树状数组,存每个数据出现的次数。一个用于维护所有数据,另一个用于维护数据是否存在(去重后的数据)。

    随着莫队在区间上的伸缩不断调整树状数组内的数据,

    然后利用树状数组的区间查询操作查询就好了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define rint register long long
    #define int long long
    using namespace std;
    int n,m,a[100005],l,r,t1[100005],t2[100005],cnt[100005],belong[100005],sum_q;
    struct node{int l,r,id,a,b,ans1,ans2;}que[1000005];
    int lowbit(int x){return x&(-x);}
    bool cmp(node xx,node yy){return belong[xx.l]==belong[yy.l]?xx.r<yy.r:xx.l<yy.l;}
    bool cmp_id(node x,node y){return x.id<y.id;}
    void update1(int x,int num){for(;x<=n;x+=lowbit(x))t1[x]+=num;}
    void update2(int x,int num){for(;x<=n;x+=lowbit(x))t2[x]+=num;}
    int query1(int x){int tot=0;for(;x;x-=lowbit(x))tot+=t1[x];return tot;}
    int query2(int x){int tot=0;for(;x;x-=lowbit(x))tot+=t2[x];return tot;}
    void add(int x){if(++cnt[x]==1)update2(x,1);update1(x,1);}
    void del(int x){if(--cnt[x]==0)update2(x,-1);update1(x,-1);}
    signed main()
    {
        scanf("%lld %lld",&n,&m);sum_q=sqrt(1ll*n*n/m);
        for(rint i=1;i<=n;++i){scanf("%lld",&a[i]);belong[i]=i/sum_q+1;}
        for(rint i=1;i<=m;++i){scanf("%lld %lld %lld %lld",&que[i].l,&que[i].r,&que[i].a,&que[i].b);que[i].id=i;}
        sort(que+1,que+m+1,cmp);l=que[1].l,r=que[1].r;
        for(rint i=l;i<=r;++i)add(a[i]);
        que[1].ans1=query1(que[1].b)-query1(que[1].a-1);
        que[1].ans2=query2(que[1].b)-query2(que[1].a-1);
        for(rint i=2;i<=m;++i)
        {
            while(l<que[i].l){del(a[l]);l++;}while(l>que[i].l){l--;add(a[l]);}
            while(r<que[i].r){r++;add(a[r]);}while(r>que[i].r){del(a[r]);r--;}
            que[i].ans1=query1(que[i].b)-query1(que[i].a-1);
            que[i].ans2=query2(que[i].b)-query2(que[i].a-1);
        }
        sort(que+1,que+m+1,cmp_id);
        for(rint i=1;i<=m;++i){cout<<que[i].ans1<<" "<<que[i].ans2<<endl;}
        return 0;
    }
    比日志里的那个正常一点
  • 相关阅读:
    linux上实现jmeter分布式压力测试(转)
    The more,the better。
    DP_括号匹配序列问题
    MySQL基础语句
    大端模式和小端模式
    C++:bitset用法
    TCP三次握手和四次握手
    静态库与动态库
    DP_最长公共子序列/动规入门
    二维数组和指针
  • 原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11253691.html
Copyright © 2020-2023  润新知