#line 1 "test/yukicoder/924.test.cpp" #define PROBLEM "https://yukicoder.me/problems/no/924" #include using namespace std; #define REP(i, n) for (int i = 0; i < (n); i++) #line 2 "library/algebra/group/Add.cpp" template struct GroupAdd { using value_type = X; static constexpr X op(const X &x, const X &y) noexcept { return x + y; } static constexpr void Rchop(X&x, const X&y){ x+=y; } static constexpr void Lchop(const X&x, X&y){ y+=x; } static constexpr X inverse(const X &x) noexcept { return -x; } static constexpr X power(const X &x, long long n) noexcept { return X(n) * x; } static constexpr X unit() { return X(0); } static constexpr bool commute = true; }; #line 2 "library/datastructure/FullyIndexableDictionary.cpp" class FullyIndexableDictionary{ int n, block; // 64個事に区切ったブロックの個数 vector bit; vector sum; // ブロック毎の累積和 bool prepared; public: FullyIndexableDictionary(){} FullyIndexableDictionary(int n) :n(n),block((n+63)>>6),bit(block,0),sum(block+1,0),prepared(false){} bool is_prepared(){ return prepared; } void set(int k){ bit[k>>6]|=1ull<<(k&63); sum[(k>>6)+1]++; } void build(){ assert(!prepared); prepared=true; for(int i=0;i>6]>>(k&63))&1); } // [0,j) の合計 int rank(int j,bool f=1){ assert(prepared); int a=sum[j>>6]+__builtin_popcountll(bit[j>>6]&((1ull<<(j&63))-1)); return (f?a:j-a); } // 0-indexed で k 番目の f の場所 int select(int k,bool f=1){ assert(prepared); if(k<0 or rank(n,f)<=k)return -1; int l=0,r=n; while(r-l>1){ int m=(l+r)>>1; (rank(m,f)>=k+1?r:l)=m; } return r-1; } // l以上で k 番目の f の場所 int select(int k,bool f,int l){ return select(rank(l,f)+k,f); } }; #line 2 "library/util/Compress.cpp" #define ALL_(v) v.begin(),v.end() template class Compress{ vector v; bool prepared; public: Compress():prepared(false){ if constexpr(Sentinel){ static_assert(std::numeric_limits::is_specialized,"cannot use Sentinel"); v={numeric_limits::min(),numeric_limits::max()}; } } Compress(const vector&w):v(w),prepared(false){ if constexpr(Sentinel){ static_assert(std::numeric_limits::is_specialized,"cannot use Sentinel"); v.push_back(numeric_limits::min()); v.push_back(numeric_limits::max()); } build(); } void add(T a){ assert(!prepared); v.push_back(a); } void build(){ assert(!prepared); prepared=true; sort(ALL_(v)); v.erase(unique(ALL_(v)),v.end()); } bool is_prepared()const{ return prepared; } int operator[](const T&a)const{ assert(prepared); auto it=lower_bound(ALL_(v),a); assert(*it==a); return distance(v.begin(),it); } int geq(const T&a)const{ assert(prepared); auto it=lower_bound(ALL_(v),a); return distance(v.begin(),it); } int gt(const T&a)const{ assert(prepared); auto it=upper_bound(ALL_(v),a); return distance(v.begin(),it); } int leq(const T&a)const{ assert(prepared); auto it=--upper_bound(ALL_(v),a); return distance(v.begin(),it); } int lt(const T&a)const{ assert(prepared); auto it=--lower_bound(ALL_(v),a); return distance(v.begin(),it); } T r(int id)const{ assert(prepared); return v[id]; } bool exist(const T&a)const{ assert(prepared); return (*lower_bound(ALL_(v),a))==a; } int size()const{return v.size();} T max()const{ return v.back(); } T min()const{ return v[0]; } friend ostream&operator<<(ostream&os, const Compress&C){ for(int i=0;i class WaveletMatrix{ protected: using U=conditional_t; static_assert(is_integral_v,"Wavelet Matrix is only for integer"); int n,memo,log; vector mat; vector zero_cnt; Compress C; vector data; constexpr U comp(const T&x)const{ if constexpr(COMPRESS){ return C.geq(x); } else{ return x; } } constexpr T uncomp(const U&a){ if constexpr(COMPRESS){ return C.r(a); } else{ return a; } } // 0-indexed で下から i bit 目 inline bool low_bit (const U&a,int i)const{ return (a>>i)&1; } // 0-indexed で上から i bit 目 inline bool high_bit(const U&a,int i)const{ return low_bit(a,log-i-1); } int nxt(int idx,int h,const U&a){ // idx の位置に a があった場合上から h bit 目でどこに行くか bool bit=high_bit(a,h); return mat[h].rank(idx,bit)+(bit?zero_cnt[h]:0); } public: WaveletMatrix(vector v,int log_=0):n(v.size()),data(v),log(log_){ vector cv(n); if constexpr(COMPRESS){ C=Compress(v); for(int i=0;i=(1ull<=0); if(mx=(1ull< lv(n),rv(n); REP_(h,log){ mat[h]=FullyIndexableDictionary(n); int l=0,r=0; REP_(i,n) if(high_bit(cv[i],h)){ rv[r++]=cv[i]; mat[h].set(i); } else lv[l++]=cv[i]; zero_cnt[h]=l; mat[h].build(); swap(lv,cv); REP_(i,r)cv[l+i]=rv[i]; } } // [l,r) の x の個数 int rank(int l,int r,const T&x){ if constexpr(COMPRESS){ if(!C.exist(x))return 0; } U a=comp(x); REP_(h,log){ l=nxt(l,h,a); r=nxt(r,h,a); } memo=l; return r-l; } int rank(int r,const T&x){ return rank(x,0,r); } // k 番目の x の index int select(int k,const T&x){ U a=comp(x); if(rank(a,n)=0;h--){ bool bit=high_bit(a,h); if(bit)k-=zero_cnt[h]; k=mat[h].select(k,bit); } return k; } // [l,r) で 0-indexed k 番目に大きい値 T kth_largest(int l,int r,int k){ if(k<0 or r-l<=k) return -1; U res=0; REP_(h,log){ int L=mat[h].rank(l); int R=mat[h].rank(r); res<<=1; if(R-L>k){ l=L+zero_cnt[h]; r=R+zero_cnt[h]; res++; } else{ k-=R-L; l-=L; r-=R; } } return uncomp(res); } T kth_smallest(int l,int r,int k){ return kth_largest(l,r,r-l-k-1); } // [l,r) で x 未満の個数 int range_freq(int l,int r,const T&upper){ U a=comp(upper); int res=0; REP_(h,log){ if(high_bit(a,h)){ int L=mat[h].rank(l,0),R=mat[h].rank(r,0); res+=R-L; } l=nxt(l,h,a); r=nxt(r,h,a); } return res; } // [l,r) で [lower,upper) の個数 int range_freq(int l,int r,const T&lower,const T&upper){ return range_freq(l,r,upper)-range_freq(l,r,lower); } optional lt(int l,int r,const T&x){ int cnt=range_freq(l,r,x); if(cnt)return kth_smallest(l,r,cnt-1); return nullopt; } optional leq(int l,int r,const T&x){ if(rank(l,r,x))return x; return lt(l,r,x); } optional geq(int l,int r,const T&x){ int cnt=r-l-range_freq(l,r,x); if(cnt)return kth_largest(l,r,cnt-1); return nullopt; } optional gt(int l,int r,const T&x){ T y; if constexpr(COMPRESS){ y=C.r(C.gt(x)); } else{ y=x+1; } return geq(l,r,y); } // セグ木などを載せる時用 // BIT は専用のライブラリを作ってあるが、一応抽象化も持っておく // 構築したものを返してるので遅そう int height()const{ return log; } vector points(int idx){ vector res(log); U a=comp(data[idx]); REP_(h,log){ idx=nxt(idx,h,a); res[h]=idx; } return res; } vector> intervals(int l,int r,const T&upper){ vector> res; U a=comp(upper); REP_(h,log){ if(high_bit(a,h)){ int L=mat[h].rank(l,0),R=mat[h].rank(r,0); res.emplace_back(h,L,R); } l=nxt(l,h,a); r=nxt(r,h,a); } return res; } vector> kth_largest_intervals(int l,int r,int k){ assert(0<=k and k> res; REP_(h,log){ int L=mat[h].rank(l); int R=mat[h].rank(r); if(R-L>k){ l=L+zero_cnt[h]; r=R+zero_cnt[h]; } else{ res.emplace_back(h,L+zero_cnt[h],R+zero_cnt[h]); k-=R-L; l-=L; r-=R; } } return res; } vector> kth_smallest_intervals(int l,int r,int k){ return kth_largest_intervals(l,r,r-l-k-1); } }; #undef REP_ #line 3 "library/datastructure/FenwickTree.cpp" template> class FenwickTree{ using G=AbelGroup; using T=typename G::value_type; int n; vector dat,raw; public: FenwickTree(){ assert(G::commute); } FenwickTree(int n):n(n){ assert(G::commute); dat=raw=vector(n,G::unit()); } FenwickTree(const vector&v):n(v.size()),raw(v),dat(v){ assert(G::commute); for(int i=1;i<=n;i++){ int j=i+(i&-i); if(j<=n)G::Rchop(dat[j-1],dat[i-1]); } } T operator[](int k)const{ return raw[k]; } T get(int k)const{ return raw[k]; } void multiply(int k,const T&x){ G::Rchop(raw[k],x); for(++k;k<=n;k+=k&-k)G::Rchop(dat[k-1],x); } void add(int k,const T&x){ multiply(k,x); } void set(int k,const T&x){ multiply(k,G::op(x,G::inverse(raw[k]))); } T prod(int k)const{ T res=G::unit(); while(k>0){ G::Rchop(res, dat[k-1]); k -= k&-k; } return res; } T sum(int k)const{ return prod(k); } T prod(int L,int R)const{ T pos=G::unit(); while(L int max_right(const F check)const{ assert(check(G::unit())); int r=0; T sum=G::unit(); int k=1; while(2*k<=n)k<<=1; while(k){ if(r+k-1>= 1; } return r; } int kth(T k)const{ return max_right( [&k](T x){ return x<=k; } ); } }; #line 4 "library/datastructure/GroupWaveletMatrix.cpp" #define REP_(i,n) for(int i=0;i<(n);i++) template class GroupWaveletMatrix:WaveletMatrix{ using super=WaveletMatrix; using super::log,super::n,super::nxt,super::comp,super::data,super::high_bit,super::mat,super::zero_cnt; using U=typename super::U; using FT=FenwickTree; using S=typename AbelGroup::value_type; vector ft; public: using super::rank,super::select,super::kth_largest,super::kth_smallest,super::range_freq,super::lt,super::leq,super::gt,super::geq; GroupWaveletMatrix(vector v):super::WaveletMatrix(v){ ft.resize(log); for(auto&p:ft)p=FT(n); } GroupWaveletMatrix(vector v,const vector&w):GroupWaveletMatrix(v){ for(int i=0;ik){ l=L+zero_cnt[h]; r=R+zero_cnt[h]; } else{ AbelGroup::Rchop(res,ft[h].sum(L+zero_cnt[h],R+zero_cnt[h])); k-=R-L; l-=L; r-=R; } } return res; } }; #undef REP_ #line 8 "test/yukicoder/924.test.cpp" using ll = long long; constexpr ll LINF = 1e18; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, q; cin >> n >> q; vector v(n); for (int i = 0; i < n; i++) cin >> v[i]; GroupWaveletMatrix> WM(v, v); while (q--) { int l, r; cin >> l >> r; l--; int k = (r - l) / 2; // 0-indexed 小さい方から k 番目の値を x にする ll x = WM.kth_smallest(l, r, k); ll res = 0; // x 未満 ll cnt1 = WM.range_freq(l, r, x); res += x * cnt1 - WM.sum(l, r, x); // x 以上 ll cnt2 = WM.range_freq(l, r, x, LINF); res += WM.sum(l, r, x, LINF) - x * cnt2; cout << res << "\n"; } }