传送门
莫队算法入门题
这里莫队讲得非常好。
每个询问的的答案 分母:区间长度
×
×
(区间长度
−1
−
1
),分子:区间内每种颜色出现次数
×
×
(出现次数
−1
−
1
)。
若
l
l
同块,以为关键字否则以
l
l
<script type="math/tex" id="MathJax-Element-222">l</script>为关键字排序。
#include<bits/stdc++.h>
#define il inline
#define ll long long
using namespace std;
const int N=5e5+5;
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
il int read(){
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=(x+(x<<2)<<1)+c-48;
return x*f;
}
char sr[1<<21],z[20];int C=-1,Z;
il void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
il void print(ll x,char cc){
if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]=cc;
}
struct nd{int l,r,id;ll A,B;}q[N];
int n,m,s,a[N],bl[N];ll sum[N],ans;
bool cmp1(nd a,nd b){return bl[a.l]==bl[b.l]?a.r<b.r:a.l<b.l;}
bool cmp2(nd a,nd b){return a.id<b.id;};
il ll sqr(ll x){return x*x;}
il void del(int x){ans-=sqr(sum[a[x]]--),ans+=sqr(sum[a[x]]);}
il void ins(int x){ans-=sqr(sum[a[x]]++),ans+=sqr(sum[a[x]]);}
il ll gcd(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
int main(){
n=read(),m=read(),s=sqrt(n);
for(int i=1;i<=n;++i) a[i]=read(),bl[i]=(i-1)/s+1;
for(int i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+m+1,cmp1);
for(int i=1,l=1,r=0;i<=m;++i){
while(l<q[i].l) del(l++);
while(l>q[i].l) ins(--l);
while(r<q[i].r) ins(++r);
while(r>q[i].r) del(r--);
if(q[i].l==q[i].r){q[i].A=0;q[i].B=1;continue;}
q[i].A=ans-(q[i].r-q[i].l+1);
q[i].B=1ll*(q[i].r-q[i].l+1)*(q[i].r-q[i].l);
ll g=gcd(q[i].A,q[i].B);q[i].A/=g,q[i].B/=g;
}
sort(q+1,q+m+1,cmp2);
for(int i=1;i<=m;++i) print(q[i].A,'/'),print(q[i].B,'\n');
Ot();return 0;
}