题解【[AHOI2013]作业】

\[ \texttt{Preface} \]

数据貌似很水,据说 \(A_i\leq n\) ,连离散化都不需要。

不知道为啥设块大小为 \(\frac{n}{\sqrt m}\) 会一直 Runtime Error on test 1,3,4 ,改成 \(\sqrt n\)\(A\) 了,据说是 \(m=0\) 的问题,但我明明特判了阿 qwq 。
\[ \texttt{Description} \]
给出一个长度为 \(n\) 的序列 \(A\) ,一共 \(m\) 次询问,每次需要回答 " 区间 \([l,r]\) 内有多少个位置上的数的大小在 \([a,b]\) 内" 以及 " 区间 \([l,r]\) 内出现的所有数中,有多少个数的大小在 \([a,b]\) 内 " 。
\[ \texttt{Solution} \]
莫队 \(+\) 树状数组。

我们知道莫队可以解决 " 区间内数的出现次数 " 这类问题。

在上文提到的,\(A_i \leq n\)

所以可以直接开个两个桶,c[x][1] 表示值为 \(x\) 的数的出现次数,c[x][2] 表示值为 \(x\) 的数有没有出现过。

然后我们发现每个询问答案要求的其实是 \(\sum\limits_{i=a}\limits^b c[i][1]\)\(\sum\limits_{i=a}\limits^b c[i][2]\) ,本质上是一个区间求和,但是它还需要支持单点修改(插入和删除)。

于是我们可以用一个 支持 \(O(\log n)\) 单点修改以及区间求和的数据结构 维护这两个桶,此时树状数组就是一个不错的选择。

时间复杂度 \(O(n \sqrt n \log n)\)
\[ \texttt{Code} \]

#include
#include
#include

#define RI register int

using namespace std;

inline int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}

const int N=100100,M=100100,MaxV=100100;

int n,m;
int S;

int block(int x)
{
    return (x-1)/S+1;
}

int a[N];

struct ask{
    int l,r;
    int a,b;
    int id;
    int ans1,ans2;
}q[M];

bool cmp(ask a,ask b)
{
    return block(a.l)==block(b.l)?a.rq[i].r)sub(r--);
        while(lq[i].l)add(--l);

        q[i].ans1=BITask(q[i].b,1)-BITask(q[i].a-1,1);
        q[i].ans2=BITask(q[i].b,2)-BITask(q[i].a-1,2);
    }

    sort(q+1,q+1+m,rebuild);

    for(RI i=1;i<=m;i++)
        printf("%d %d\n",q[i].ans1,q[i].ans2);

    return 0;
}

\[ \texttt{Thanks} \ \texttt{for} \ \texttt{watching} \]

你可能感兴趣的:(题解【[AHOI2013]作业】)