【bzoj2038】[国家集训队2010]小Z的袜子 莫队

时间:2021-08-02 06:52:25

莫队:就是一坨软软的有弹性的东西Duang~Duang~Duang~

为了防止以左端点为第一关键字以右端点为第二关键字使右端点弹来弹去,所以让左端点所在块为关键字得到O(n1.5)的时间效率,至于分块的优化,根本用不到。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#define MAXN 50005
using namespace std;
typedef long long LL;
struct Query
{
LL l,r,a,b,id;
}query[MAXN];
LL pos[MAXN];
int cmp(const Query a,const Query b)
{
return a.id<b.id;
}
int comp(const Query a,const Query b)
{
if(pos[a.l]<pos[b.l])return ;
if(pos[a.l]==pos[b.l]&&a.r<b.r)return ;
return ;
}
LL a[MAXN],s[MAXN],n,m,len,l,r,ans;
LL gcd(LL x,LL y)
{
return y==?x:gcd(y,x%y);
}
inline void did(LL x,LL di)
{
ans-=s[a[x]]*s[a[x]];
s[a[x]]+=di;
ans+=s[a[x]]*s[a[x]];
}
inline void work()
{
for(LL i=;i<=m;i++)
{
while(l<query[i].l)did(l++,-);
while(l>query[i].l)did(--l,);
while(r<query[i].r)did(++r,);
while(r>query[i].r)did(r--,-);
if(l==r)
{
query[i].a=;
query[i].b=;
continue;
}
LL son=ans-(r-l+);
LL mo=(LL)(r-l)*(r-l+);
LL k=gcd(son,mo);
query[i].a=son/k;
query[i].b=mo/k;
}
}
int main()
{
freopen("hose.in", "r", stdin);
freopen("hose.out", "w", stdout);
scanf("%lld%lld",&n,&m);
len=(LL)(sqrt(n+0.5));
l=r=ans=;
for(LL i=;i<=n;i++)
{
scanf("%lld",&a[i]);
pos[i]=(i-)/len+;
}
s[a[]]++;
for(LL i=;i<=m;i++)
{
scanf("%lld%lld",&query[i].l,&query[i].r);
query[i].id=i;
}
sort(query+,query++m,comp);
work();
sort(query+,query+m+,cmp);
for(LL i=;i<=m;i++)
printf("%lld/%lld\n",query[i].a,query[i].b);
return ;
}