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 ",ans[i]-1); //here很神,发现不改比样例都大1 }