0w1

CFR 86 D. Powerful array ( Mo's Algorithm, Math )

Problem - D - Codeforces

題意:
給一個長度為 N 的數列 A[]。T 筆詢問,問對 [ L, R ] 中存在的所有相異數值 s,SUM( K[ s ] * K[ s ] * s ) 是多少。K[ s ] 代表 [ L, R ] 區間中,s 出現的次數。

資料規模:
First line contains two integers n and t (1 ≤ n, t ≤ 200000) — the array length and the number of queries correspondingly.
Second line contains n positive integers ai (1 ≤ ai ≤ 1e6) — the elements of the array.
Next t lines contain two positive integers l, r (1 ≤ l ≤ r ≤ n) each — the indices of the left and the right ends of the corresponding subarray.

解法:
看起來就很莫隊,但不能每次到暴力重算。
考慮一下變化的差:
( ( K[ s ] + 1 )^2 - ( K[ s ] ) ) * s = ( 2 * K[ s ] + 1 ) * s
利用這點,就真的是個裸的莫隊了。

時間 / 空間複雜度:
O( N^1.5 + T^1.5 ) / O( N + T )

#include <bits/stdc++.h>
using namespace std;

const int MAXN = ( int ) 2e5;
const int MAXT = ( int ) 2e5;
const int MAXA = ( int ) 1e6;
const int BLK = 500;

int N, T;
int A[ MAXN ];
int L[ MAXT ], R[ MAXT ];
int qord[ MAXT ];

int K[ MAXA + 1 ];
long long ans[ MAXT ];

signed main(){
  ios::sync_with_stdio( 0 );
  cin >> N >> T;
  for( int i = 0; i < N; ++i ){
    cin >> A[ i ];
  }
  for( int i = 0; i < T; ++i ){
    cin >> L[ i ] >> R[ i ];
    --L[ i ]; // [ L, R )
    qord[ i ] = i;
  }
  sort( qord, qord + T, [ & ]( int i, int j ){
      if( L[ i ] / BLK != L[ j ] / BLK ) return L[ i ] / BLK < L[ j ] / BLK;
      return R[ i ] < R[ j ]; } );
  for( int ti = 0, lb = 0, rb = 0; ti < T; ++ti ){ // [ lb, rb )
    static long long cur = 0;
    while( L[ qord[ ti ] ] < lb ){
      --lb;
      cur += ( 2LL * K[ A[ lb ] ] + 1 ) * A[ lb ];
      ++K[ A[ lb ] ];
    }
    while( lb < L[ qord[ ti ] ] ){
      cur -= ( 2LL * ( K[ A[ lb ] ] - 1 ) + 1 ) * A[ lb ];
      --K[ A[ lb ] ];
      ++lb;
    }
    while( R[ qord[ ti ] ] < rb ){
      --rb;
      cur -= ( 2LL * ( K[ A[ rb ] ] - 1 ) + 1 ) * A[ rb ];
      --K[ A[ rb ] ];
    }
    while( rb < R[ qord[ ti ] ] ){
      cur += ( 2LL * K[ A[ rb ] ] + 1 ) * A[ rb ];
      ++K[ A[ rb ] ];
      ++rb;
    }
    ans[ qord[ ti ] ] = cur;
  }
  for( int i = 0; i < T; ++i ){
    cout << ans[ i ] << "\n";
  }
  return 0;
}