传说中的莫队算法 时间 n*sqrt(n);
没的修改 然后从前往后跑 重复的就节约下来了
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define LL long long
#define MAXN 50010
#define inf 1000000000.0
struct node
{
int l,r,id;
}q[MAXN];
int pos[MAXN];
int cnt[MAXN];
int num[MAXN];
LL ansl[MAXN],ansr[MAXN];
bool cmp(node a,node b)
{
if(pos[a.l]==pos[b.l])
return a.r<b.r;
return pos[a.l]<pos[b.l];
}
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i; //第几个
}
int sz=sqrt(n);
for(int i=1;i<=n;i++)
pos[i]=i/sz; //分块中第几个
sort(q+1,q+m+1,cmp);
memset(cnt,0,sizeof(cnt));
int l,r;
LL ans;
l=r=1;
ans=0;
cnt[num[1]]++; //第一个放进去
for(int i=1;i<=m;i++)
{
if(r<q[i].r)
{
for(int k=r+1;k<=q[i].r;k++)
{
ans -= cnt[num[k]] *(cnt[num[k]]-1);
cnt[num[k]]++;
ans += cnt[num[k]] *(cnt[num[k]]-1);
}
}
else if(r>q[i].r)
{
for(int k=r;k>q[i].r;k--)
{
ans -= cnt[num[k]]*(cnt[num[k]]-1);
cnt[num[k]]--;
ans += cnt[num[k]]*(cnt[num[k]]-1);
}
}
if(l<q[i].l)
{
for(int k=l;k<q[i].l;k++)
{
ans -= cnt[num[k]]*(cnt[num[k]]-1);
cnt[num[k]]--;
ans += cnt[num[k]]*(cnt[num[k]]-1);
}
}
else if(l>q[i].l)
{
for(int k=l-1;k>=q[i].l;k--)
{
ans -= cnt[num[k]] *(cnt[num[k]]-1);
cnt[num[k]]++;
ans += cnt[num[k]] *(cnt[num[k]]-1);
}
}
l = q[i].l;
r = q[i].r;
LL len = q[i].r-q[i].l+1;
LL tot = len*(len -1);
LL d = gcd(ans,tot);
ansl[q[i].id]=ans/d;
ansr[q[i].id]=tot/d;
}
for(int i=1;i<=m;i++)
printf("%lld/%lld\n",ansl[i],ansr[i]);
}
return 0;
}