luogu 2709小b的询问--莫队

https://www.luogu.org/problemnew/show/P2709

无修改的莫队几乎没有什么太高深的套路,比较模板吧,大多都是在那两个函数上动手脚。

这题询问每一种数字数量的平方和,那么我们在左移或右移的时候记录一下就好了,当每一种数字的种类数加1或减1的时候,我们需要减去以前这个数对答案的影响,加上现在对答案的影响。

假设原来数字a的种类数为k,如今又加入一个a,那么先ans-=k^2,然后ans+=(k+1)^2.,删除同理。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define N int(5e5+2)
#define M int(2e5+2)
using namespace std;
struct ahah{
    int L,R,p,f;
}ask[N];
int answer,n,m,q,a[N],cnt[N],ans[N],k;
bool cmp(ahah a,ahah b){ return a.p<b.p; }
bool comp(ahah a,ahah b){ return a.L/k==b.L/k?a.R<b.R:a.L<b.L; }
void remove(int pos)
{
    answer-=cnt[a[pos]]*cnt[a[pos]],--cnt[a[pos]],answer+=cnt[a[pos]]*cnt[a[pos]]; 
}
void add(int pos)
{
    answer-=cnt[a[pos]]*cnt[a[pos]],++cnt[a[pos]],answer+=cnt[a[pos]]*cnt[a[pos]]; 
}
int main()
{
    scanf("%d%d%d",&n,&q,&m);
    k=sqrt(n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=q;i++)scanf("%d%d",&ask[i].L,&ask[i].R),ask[i].p=i;
    sort(ask+1,ask+1+q,comp);
    int curl=1,curr=0;
    for(int i=1;i<=q;i++)
    {
        int L=ask[i].L,R=ask[i].R;
        while(curl<L)remove(curl++);
        while(curl>L)add(--curl);
        while(curr<R)add(++curr);
        while(curr>R)remove(curr--);
        ans[ask[i].p]=answer;
    }
    for(int i=1;i<=q;i++)printf("%d\n",ans[i]-1);    //here很神,发现不改比样例都大1 
}

 

posted @ 2018-08-07 21:54  Manjusaka丶梦寒  阅读(439)  评论(0编辑  收藏  举报