Problem - 1579E2 - Codeforces
Array Optimization by Deque - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
树状数组解法
- 将 a i a_i ai插入到队头,贡献为:原队列中所有比 a i a_i ai小的数的数量
- 将 a i a_i ai插入到队尾,贡献为:原队列中所有比 a i a_i ai大的数的数量
可以发现对于每一次插入a值,影响插入的只跟已经放入的大于a或小于a的数量有关。
需要一个数据结构,满足:动态修改、查询。可以发现树状数组可以做这些操作,不过 a i a_i ai较大,开不下数组,可以离散化。
在离散化后,本题转为:查询 a i a_i ai前面的数量和后面的数量(大于/小于)。如果前面的数量小,就插前面,否则插入后面,将答案进行更新。
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <ctime>
#include <random>
#include <sstream>
#include <numeric>
#include <stdio.h>
#include <functional>
#include <bitset>
#include <algorithm>
using namespace std;
#define Multiple_groups_of_examples
#define int_to_long_long
#define IOS std::cout.tie(0);std::cin.tie(0)->sync_with_stdio(false); // 开IOS,需要保证只使用Cpp io流 *
#define dbgnb(a) std::cout << #a << " = " << a << '\n';
#define dbgtt cout<<" !!!test!!! "<<'\n';
#define rep(i,x,n) for(int i = x; i <= n; i++)
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define vf first
#define vs second
typedef long long LL;
#ifdef int_to_long_long
#define int long long
#endif
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 21;
template <class T>
struct Fenwick {
int n;
vector<T> a;
Fenwick(const int &n = 0) : n(n), a(n, T()) {}
void modify(int i, T x) {
for (i++; i <= n; i += i & -i) {
a[i - 1] += x;
}
}
T get(int i) {
T res = T();
for (; i > 0; i -= i & -i) {
res += a[i - 1];
}
return res;
}
T sum(int l, int r) { // [l, r] *这里已经改过
return get(r + 1) - get(l);
}
int kth(T k) {
int x = 0;
for (int i = 1 << __lg(n); i; i >>= 1) {
if (x + i <= n && k >= a[x + i - 1]) {
x += i;
k -= a[x - 1];
}
}
return x;
}
};
void inpfile();
void solve() {
int n; cin>>n;
vector<int> a(n);
for(auto &t: a) cin>>t;
// 离散化
vector<int> id(a);
sort(all(id));
id.erase(unique(all(id)), id.end());
vector<int> last(n);
for(int i = 0; i < n; ++i) last[i] = lower_bound(all(id), a[i]) - id.begin() + 1;
Fenwick<int> tr(n + 21);
int sum = 0;
for(int i = 0; i < n; ++i) {
// lv表示插入队首,rv表示插入队尾的逆序对值
int lv = tr.sum(1, last[i] - 1), rv = tr.sum(last[i] + 1, n + 20);
sum += min(lv, rv);
tr.modify(last[i], 1);
}
cout<<sum<<endl;
}
#ifdef int_to_long_long
signed main()
#else
int main()
#endif
{
#ifdef Multiple_groups_of_examples
int T; cin>>T;
while(T--)
#endif
solve();
return 0;
}
void inpfile() {
#define mytest
#ifdef mytest
freopen("ANSWER.txt", "w",stdout);
#endif
}
pbds 解法
pbds库学习笔记(优先队列、平衡树、哈希表) - 知乎 (zhihu.com)
发现核心就是求排名,平衡树即可。这里提供pbds的代码:
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <ctime>
#include <random>
#include <sstream>
#include <numeric>
#include <stdio.h>
#include <functional>
#include <bitset>
#include <algorithm>
// pbds
#include <bits/extc++.h>
using namespace __gnu_cxx;
using namespace __gnu_pbds;
using namespace std;
#define Multiple_groups_of_examples
#define int_to_long_long
#define IOS std::cout.tie(0);std::cin.tie(0)->sync_with_stdio(false); // 开IOS,需要保证只使用Cpp io流 *
#define dbgnb(a) std::cout << #a << " = " << a << '\n';
#define dbgtt cout<<" !!!test!!! "<<'\n';
#define rep(i,x,n) for(int i = x; i <= n; i++)
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define vf first
#define vs second
typedef long long LL;
#ifdef int_to_long_long
#define int long long
#endif
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 21;
// pbds
typedef tree<PII, null_type, less<PII>, rb_tree_tag, tree_order_statistics_node_update> Tree;
void inpfile();
void solve() {
int n; cin>>n;
Tree tr;
int sum = 0;
for(int i = 0; i < n; ++i) {
int t; cin>>t;
int lv = tr.order_of_key({t, 0}), rv = i - tr.order_of_key({t, n});
sum += min(lv, rv);
tr.insert({t, i});
}
cout<<sum<<endl;
}
#ifdef int_to_long_long
signed main()
#else
int main()
#endif
{
#ifdef Multiple_groups_of_examples
int T; cin>>T;
while(T--)
#endif
solve();
return 0;
}
void inpfile() {
#define mytest
#ifdef mytest
freopen("ANSWER.txt", "w",stdout);
#endif
}
pbds库学习笔记(优先队列、平衡树、哈希表) - 知乎 (zhihu.com)