P2709 小B的询问(莫队算法)

题目描述

小B 有一个长为 nn 的整数序列 aa,值域为 [1,k][1,k]。
他一共有 mm 个询问,每个询问给定一个区间 [l,r][l,r],求:

sumlimits_{i=1}^k c_i^2i=1kci2

其中 c_ici 表示数字 ii 在 [l,r][l,r] 中的出现次数。
小B请你帮助他回答询问。

输入格式

第一行三个整数 n,m,kn,m,k。

第二行 nn 个整数,表示 小B 的序列。

接下来的 mm 行,每行两个整数 l,rl,r。

输出格式

输出 mm 行,每行一个整数,对应一个询问的答案。

题解:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
ll a[maxn];
ll cnt[maxn];
ll belong[maxn];
ll n,m,k,size,bnum,now,ans[maxn];



struct query {
    ll l,r,id;
}q[maxn];
int cmp (query a,query b) {
    return (belong[a.l]^belong[b.l])?belong[a.l]<belong[b.l]:((belong[a.l]&1)?a.r<b.r:a.r>b.r);
}
void add (int p) {
    //if (!cnt[a[p]])
    //    ++now;
    ++cnt[a[p]];
    now+=2*cnt[a[p]]-1;
}
void del (int p) {
    --cnt[a[p]];
    now-=2*cnt[a[p]]+1;
    //if (!cnt[a[p]])
    //    --now;
}
int main () {
    scanf("%lld%lld%lld",&n,&m,&k);
    size=sqrt(n);
    bnum=n/size+(n%size>0);
    for (int i=1;i<=bnum;i++)
        for (int j=(i-1)*size+1;j<=i*size;j++)
            belong[j]=i;
    for (int i=1;i<=n;i++) scanf("%lld",a+i);
    for (int i=1;i<=m;i++) {
        scanf("%lld%lld",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    ll l=1,r=0;
    for (int i=1;i<=m;i++) {
        int ql=q[i].l;
        int qr=q[i].r;
        while (l<ql) del(l++);
        while (l>ql) add(--l);
        while (r<qr) add(++r);
        while (r>qr) del(r--); 
        ans[q[i].id]=now; 
    }
    for (int i=1;i<=m;i++) printf("%lld
",ans[i]);
}
原文地址:https://www.cnblogs.com/zhanglichen/p/13565041.html