有了上一题的铺垫,这题就是一道莫队的裸题,直接用和上一题一样的套路搞就行了。
不过莫队的sort好像有些什么神奇的trick:如果两个询问左端点所在的块相同,就把右端点按左端点所在块的奇偶性分类排序,就是下面那样:(至于为什么,我也不知道)
bool operator < (const note lyf) const {return (wz[l]<wz[lyf.l])||(wz[l]==wz[lyf.l]&&(wz[l]&1?r<lyf.r:r>lyf.r));}
剩下的就是和上一题差不多的莫队了。
附上AC代码:
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=5e4+10;
int n,m,k,size,c[N],wz[N];
struct note{
int l,r,pos;
bool operator < (const note lyf) const {return (wz[l]<wz[lyf.l])||(wz[l]==wz[lyf.l]&&(wz[l]&1?r<lyf.r:r>lyf.r));}
}a[N];
ll ans,out[N],s[N];
inline char nc(void){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &a){
static char c=nc();int f=1;
for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
for (a=0;isdigit(c);a=(a<<3)+(a<<1)+c-'0',c=nc());
a*=f;return;
}
inline void updata(int x,int w){return (void)(ans+=s[c[x]]*2ll*w+1,s[c[x]]+=1ll*w);}
int main(void){
read(n),read(m),read(k),size=sqrt(n);
for (int i=1; i<=n; ++i) read(c[i]),wz[i]=(i-1)/size+1;
for (int i=1; i<=m; ++i) read(a[i].l),read(a[i].r),a[i].pos=i;
sort(a+1,a+1+m);
for (int i=1,l=1,r=0; i<=m; ++i){
for (; r<a[i].r; ++r) updata(r+1,1);
for (; r>a[i].r; --r) updata(r,-1);
for (; l<a[i].l; ++l) updata(l,-1);
for (; l>a[i].l; --l) updata(l-1,1);
out[a[i].pos]=ans;
}
for (int i=1; i<=m; ++i) printf("%lld\n",out[i]);
return 0;
}