洛谷P2709 小B的询问 莫队做法

题干

这个是用来学莫队的例题,洛谷详解

需要注意的一点,一定要分块!不然会慢很多(直接TLE)

其中分块只在排序的时候要用,并且是给问题右端点分块

再就是注意add与del函数里的操作,增加数量不提,ans的加减可以用完全平方公式推出

上代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define NUM 50010
using namespace std;
int n,m,k;
long long ans,blo;//当前的答案,每个块内点的数量 
int a[NUM]; 
long long sum[NUM],anss[NUM];//每个数的出现次数,对于每个问题的对应答案 
struct wen{
    long long l,r,num;
};
wen q[NUM];
void add( int x ){
    sum[a[x]]++;
    ans += sum[a[x]] * 2 - 1;
}
void del( int x ){
    sum[a[x]]--;
    ans -= sum[a[x]] * 2 + 1;
    //a^2 = (a-1)^2+2a-1
}
bool cmp( wen gu1,wen gu2 ){
    if( gu1.r/blo != gu2.r/blo ) return gu1.r < gu2.r;
    return gu1.l < gu2.l;
}
int main(){
    cin >> n >> m >> k;
    for( int i = 1;i <= n;i++ )
        cin >> a[i];
    for( int i = 1;i <= m;i++ ){
        cin >> q[i].l >> q[i].r;
        q[i].num = i;
    }
    blo = sqrt(n);
    sort( q+1,q+m+1,cmp );
    long long l = 1,r = 0,ql,qr;
    for( int i = 1;i <= m;i++ ){
        ql = q[i].l;qr = q[i].r;
        while( l < ql ){
            del(l);
            l++;
        }
        while( r > qr ){
            del(r);
            r--;
        }
        //因为add函数是从a^2 = (a-1)^2 + 2a -1,所以先位移再跑函数 
        while( l > ql ){
            l--;
            add(l);
        }
        while( r < qr ){
            r++;
            add(r);
        }
        anss[q[i].num] = ans;
    }
    for( int i = 1;i <= m;i++ )
        cout << anss[i] << endl;
    return 0;
}

 

posted @ 2022-02-09 19:20  little_sheep_xiaoen  阅读(44)  评论(0编辑  收藏  举报