开坑莫队,个人感觉莫队的操作有点类似于分块,就是把原数组分成
O(n√)
块,然后对于排序后的询问,移动
l
和
至于莫队的时间复杂度为什么是 O(n32) ,可以参照hzwer大佬的博客。
然后这题就是一道莫队的裸题了,还没有修改,直接水掉就行了。
附上AC代码:
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=5e4+10;
int n,m,c[N],wz[N],size;
struct note{
int l,r,pos;
ll a,b;
bool operator < (const note lyf) const {return wz[l]==wz[lyf.l]?r<lyf.r:l<lyf.l;}
}a[N];
ll ans,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());
return (void)(a*=f);
}
inline void updata(int x,int w){return (void)(ans-=1ll*s[c[x]]*(s[c[x]]-1),s[c[x]]+=w,ans+=1ll*s[c[x]]*(s[c[x]]-1));}
inline ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
inline bool cmp(note a,note b){return a.pos<b.pos;}
int main(void){
read(n),read(m),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);
if (a[i].l==a[i].r){a[i].a=0,a[i].b=1;continue;}
a[i].a=ans,a[i].b=1ll*(a[i].r-a[i].l+1)*(a[i].r-a[i].l);
ll tmp=gcd(a[i].a,a[i].b);a[i].a/=tmp,a[i].b/=tmp;
}
sort(a+1,a+1+m,cmp);
for (int i=1; i<=m; ++i) printf("%lld/%lld\n",a[i].a,a[i].b);
return 0;
}