多校补不动的某人又来点技能树了。。
一直以为莫队是个数据结构,现在才知道,原来是一个算法。。
它是一个用来做离线询问的算法,使用分块的思想降低了时间复杂度。要使用它,还必须快速的完成当前状态到下个状态的转换
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, last_l = 1, last_r = 0;
ll ans, p;
int color[50010], block[50010];
ll sum[50010];
struct os{
ll part, l, r, nume, deno;//nume指分子,deno指分母
}q[50010];
bool cmp1(os xx, os yy){
if (block[xx. l] < block[yy. l])
return true;
if (block[xx. l] > block[yy. l])
return false;
return xx. r < yy. r;
}
bool cmp2(os xx, os yy){
return xx. part < yy. part;
}
inline ll gcd(ll x, ll y){
if (! y)
return x;
return gcd(y, x % y);
}
int main(){
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i ++)
scanf("%d", &color[i]);
block[0] = sqrt(n);
for (int i = 1; i <= n; i ++)
block[i] = (i - 1) / block[0] + 1;
for (int i = 1; i <= m; i ++){
scanf("%d %d", &q[i]. l, &q[i]. r),
q[i]. part = i;
}
sort(q + 1, q + m + 1, cmp1);
for (int i = 1; i <= m; i ++){
q[i]. deno = (q[i]. r - q[i]. l + 1) * (q[i]. r - q[i]. l);
if (last_r < q[i]. r){
for (int j = last_r + 1; j <= q[i]. r; j ++){
ans += ((sum[color[j]] << 1) + 1);
sum[color[j]] ++;
}
}
if (last_r > q[i]. r){
for (int j = last_r; j > q[i]. r; j --){
ans -= ((sum[color[j]] << 1) - 1);
sum[color[j]] --;
}
}
if (last_l > q[i]. l){
for (int j = last_l - 1; j >= q[i]. l; j --){
ans += ((sum[color[j]] << 1) + 1);
sum[color[j]] ++;
}
}
if (last_l < q[i]. l){
for (int j = last_l; j <q[i]. l; j ++){
ans -= ((sum[color[j]] << 1) - 1);
sum[color[j]] --;
}
}
q[i]. nume = ans - (q[i]. r - q[i]. l + 1);
last_l = q[i]. l;
last_r = q[i]. r;
}
sort(q + 1, q + m + 1, cmp2);
for (int i = 1; i <= m; i ++){
if (! q[i]. nume){
printf("0/1\n");
continue;
}
p = gcd(q[i]. nume, q[i]. deno);
printf("%lld/%lld\n", q[i]. nume / p, q[i]. deno / p);
}
return 0;
}