用这个玩意就有个要求 就是要能快速用[L, R]的信息得到[L-1, R], [L+1, R]等相邻区间的信息 然后队询问离线 分块处理
把n分成sqrt(n)块 然后按照l把每一个询问放进块里 同一个块里的询问保证r递增 这样每一l移动的长度至多是sqrt(n)*m r的移动每一块是O(n) 最多移动sqrt(n) * n 则总复杂度为O((n+m) * sqrt(n))
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#define SF scanf
#define PF printf
using namespace std;
typedef long long LL;
const int MAXN = 50000;
struct Node {
int l, r, id;
LL a, b;
bool operator < (const Node &t) const {
return id < t.id;
}
} Q[MAXN+10];
int cnt[MAXN+10], A[MAXN+10], block, n, m, L = 1, R;
LL T;
bool cmp(const Node &a, const Node &b) {
if(a.l / block == b.l / block) return a.r < b.r;
return a.l < b.l;
}
inline int gcd(LL a, LL b) {
while(b) {
LL r = a % b; a = b; b = r;
}
return a;
}
void up(int x, int val) {
T -= cnt[A[x]] * cnt[A[x]];
cnt[A[x]] += val;
T += cnt[A[x]] * cnt[A[x]];
}
int main() {
SF("%d%d", &n, &m);
block = (int)(sqrt(n) + 1e-7);
for(int i = 1; i <= n; i++) SF("%d", &A[i]);
for(int i = 1; i <= m; i++) {
SF("%d%d", &Q[i].l, &Q[i].r); Q[i].id = i;
}
sort(Q+1, Q+1+m, cmp);
for(int i = 1; i <= m; i++) {
while(R < Q[i].r) up(++R, 1);
while(R > Q[i].r) up(R--, -1);
while(L < Q[i].l) up(L++, -1);
while(L > Q[i].l) up(--L, 1);
if(Q[i].l == Q[i].r) {
Q[i].a = 0; Q[i].b = 1; continue;
}
Q[i].a = T - (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 GCD = gcd(Q[i].a, Q[i].b);
Q[i].a /= GCD; Q[i].b /= GCD;
}
sort(Q+1, Q+1+m);
for(int i = 1; i <= m; i++) PF("%lld/%lld\n", Q[i].a, Q[i].b);
}