求区间出现符合要求的三元组数量:3个不同位置,元素的值相同。

#include <bits/stdc++.h>
#define N 200050
using namespace std;
int n, m, i, j, k, p, l, r, x, y, a[N], c[N];
long long s, ans[N];
struct AB{
    int x, y, i, p;
    bool operator < (const AB &A) const{
        if(p != A.p) return p < A.p;
        return y < A.y;
    }
} d[N];
void add(int x){
    if(++c[x] > 2) s += 3ll*(c[x]-1)*(c[x]-2)/6;
}//出现至少3个,增加差值:选3个,最高位变成3
void del(int x){
    if(--c[x] > 1) s -= 3ll*c[x]*(c[x]-1)/6;
}//减少前至少3个,减少差值:选3个除以6
int main(){
    scanf("%d%d", &n, &m);
    for(i=1; i<=n; i++){
        scanf("%d", &a[i]);
    }
    p = sqrt(n);
    for(i=1; i<=m; i++){
        scanf("%d%d", &d[i].x, &d[i].y);
        d[i].i = i, d[i].p = d[i].x / p;
    }
    sort(d+1, d+m+1);
    l = r = c[a[1]] = 1, s = 0;
    for(i=1; i<=m; i++){
        x = d[i].x, y = d[i].y;
        while(r < y) add(a[++r]);
        while(l > x) add(a[--l]);
        while(l < x) del(a[l++]);
        while(r > y) del(a[r--]);
        ans[d[i].i] = s;
    }//先扩展区间,再缩小区间
    for(i=1; i<=m; i++){
        printf("%lld\n", ans[i]);
    }
    return 0;
}

作者 crxis

发表回复