結果
| 問題 |
No.404 部分門松列
|
| ユーザー |
|
| 提出日時 | 2018-03-25 13:34:42 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,559 ms / 2,000 ms |
| コード長 | 4,302 bytes |
| コンパイル時間 | 1,554 ms |
| コンパイル使用メモリ | 124,676 KB |
| 実行使用メモリ | 64,000 KB |
| 最終ジャッジ日時 | 2024-06-25 05:50:21 |
| 合計ジャッジ時間 | 26,441 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 31 |
ソースコード
#define _USE_MATH_DEFINES
#include <cstdio>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <complex>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <limits>
#include <climits>
#include <cfloat>
#include <functional>
#include <iterator>
using namespace std;
// セグメント木
class SegmentTree
{
private:
typedef tuple<int, int, long long> T1;
typedef int T2;
// データの初期値、以下の条件を満たすこと
// uniteData(v, INIT_DATA) == v
static const T1 INIT_DATA;
// 前回の値がprevである要素に対して、
// パラメータxを用いた更新処理を適用した後の計算結果を返す
T1 updateData(T1 prev, T2 x){
get<0>(prev) -= x;
get<1>(prev) += x;
get<2>(prev) = get<0>(prev) * (long long) get<1>(prev);
return prev;
}
// 2つの区間の計算結果v1,v2に対して、
// その2つの区間を統合した区間における計算結果を返す
T1 uniteData(T1 v1, T1 v2){
get<0>(v1) += get<0>(v2);
get<1>(v1) += get<1>(v2);
get<2>(v1) += get<2>(v2);
return v1;
}
int n;
vector<T1> data;
void updateTree(int a, int k, int l, int r, T2 x){
if(a == l && a == r){
data[k] = updateData(data[k], x);
}
else if(l <= a && a <= r){
updateTree(a, k*2+1, l, (l+r)/2, x);
updateTree(a, k*2+2, (l+r+1)/2, r, x);
data[k] = uniteData(data[k*2+1], data[k*2+2]);
}
}
T1 getValue(int a, int b, int k, int l, int r){
if(a <= l && r <= b){
return data[k];
}
else if(a <= r && l <= b){
T1 v1 = getValue(a, b, k*2+1, l, (l+r)/2);
T1 v2 = getValue(a, b, k*2+2, (l+r+1)/2, r);
return uniteData(v1, v2);
}
else{
return INIT_DATA;
}
}
public:
SegmentTree(int n0){
n = 1;
while(n < n0)
n *= 2;
data.assign(2*n-1, INIT_DATA);
}
SegmentTree(const vector<T1>& v) : SegmentTree((int)v.size()){
for(unsigned i=0; i<v.size(); ++i)
data[n-1+i] = v[i];
for(int k=n-2; k>=0; --k)
data[k] = uniteData(data[k*2+1], data[k*2+2]);
}
// a番目の要素にパラメータxによる更新処理を適用
void update(int a, T2 x){
updateTree(a, 0, 0, n-1, x);
}
// 区間[a,b]の計算結果を返す
T1 getValue(int a, int b){
return getValue(a, b, 0, 0, n-1);
}
};
const tuple<int, int, long long> SegmentTree::INIT_DATA = make_tuple(0, 0, 0);
int normalize(vector<int>& a, vector<int>& b, vector<int>& c)
{
int na = a.size();
int nb = b.size();
int nc = c.size();
map<int, int> conv;
for(int i=0; i<na; ++i)
conv[a[i]];
for(int i=0; i<nb; ++i)
conv[b[i]];
for(int i=0; i<nc; ++i)
conv[c[i]];
int cnt = 0;
for(auto& p : conv){
p.second = cnt;
++ cnt;
}
for(int i=0; i<na; ++i)
a[i] = conv[a[i]];
for(int i=0; i<nb; ++i)
b[i] = conv[b[i]];
for(int i=0; i<nc; ++i)
c[i] = conv[c[i]];
return cnt;
}
int main()
{
int n;
cin >> n;
vector<int> a(n);
for(int i=0; i<n; ++i)
cin >> a[i];
int q;
cin >> q;
vector<int> low(q), high(q);
for(int i=0; i<q; ++i)
cin >> low[i] >> high[i];
int m = normalize(a, low, high);
vector<tuple<int, int, long long> > v(m);
for(int i=0; i<n; ++i)
++ get<0>(v[a[i]]);
SegmentTree st(v);
vector<long long> cnt(m+1, 0);
for(int i=0; i<n; ++i){
auto t1 = st.getValue(0, a[i] - 1);
auto t2 = st.getValue(a[i] + 1, m - 1);
cnt[a[i]+1] += get<0>(t1) * (long long) get<1>(t1) - get<2>(t1);
cnt[a[i]+1] += get<0>(t2) * (long long) get<1>(t2) - get<2>(t2);
st.update(a[i], 1);
}
for(int i=0; i<m; ++i)
cnt[i+1] += cnt[i];
for(int i=0; i<q; ++i){
long long ans = cnt[high[i]+1] - cnt[low[i]];
cout << ans << endl;
}
return 0;
}