C. Optimal Insertion

目录

1.Problem

2.Input

3.Output

4.Examples

4.1input

4.2output

5.Code

6.Conclusion


1.Problem

You are given two arrays of integers a1,a2,…,ana1,a2,…,an and b1,b2,…,bmb1,b2,…,bm.

You need to insert all elements of bb into aa in an arbitrary way. As a result you will get an array c1,c2,…,cn+mc1,c2,…,cn+m of size n+mn+m.

Note that you are not allowed to change the order of elements in aa, while you can insert elements of bb at arbitrary positions. They can be inserted at the beginning, between any elements of aa, or at the end. Moreover, elements of bb can appear in the resulting array in any order.

What is the minimum possible number of inversions in the resulting array cc? Recall that an inversion is a pair of indices (i,j)(i,j) such that i<ji<j and ci>cjci>cj.

2.Input

Each test contains multiple test cases. The first line contains the number of test cases tt (1≤t≤1041≤t≤104). Description of the test cases follows.

The first line of each test case contains two integers nn and mm (1≤n,m≤1061≤n,m≤106).

The second line of each test case contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤1091≤ai≤109).

The third line of each test case contains mm integers b1,b2,…,bmb1,b2,…,bm (1≤bi≤1091≤bi≤109).

It is guaranteed that the sum of nn for all tests cases in one input doesn't exceed 106106. The sum of mm for all tests cases doesn't exceed 106106 as well.

3.Output

For each test case, print one integer — the minimum possible number of inversions in the resulting array cc.

4.Examples

4.1input

3
3 4
1 2 3
4 3 2 1
3 3
3 2 1
1 2 3
5 4
1 3 5 3 1
4 3 6 1

4.2output

0
4
6

5.Code

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

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = 1000005;
const int MAXM = 1000005;
const int MAXNODE = 2100000;

int n, m;
int a[MAXN], b[MAXM], cnt[MAXNODE][2], mina[MAXNODE], tp[MAXNODE];
pii p[MAXN];

namespace bit {
    int val[MAXN];

    void add(int x, int c) {
        for (; x <= n; x += (x & (-x))) val[x] += c;
    }

    int ask(int x) {
        int ret = 0;
        for (; x; x -= (x & (-x))) ret += val[x];
        return ret;
    }
}

void update(int id) {
    cnt[id][0] = cnt[id << 1][0] + cnt[id << 1 | 1][0];
    cnt[id][1] = cnt[id << 1][1] + cnt[id << 1 | 1][1];
    mina[id] = min(mina[id << 1] + cnt[id << 1 | 1][0], mina[id << 1 | 1] + cnt[id << 1][1]);
}

void build(int id, int l, int r) {
    if (l == r) {
        if (!l) cnt[id][0] = 1, cnt[id][1] = 0, mina[id] = 0;
        else cnt[id][0] = 0, cnt[id][1] = mina[id] = 1;
        return;
    }
    int mid = (l + r) / 2;
    build(id << 1, l, mid);
    build(id << 1 | 1, mid + 1, r);
    update(id);
}

void change(int id, int l, int r, int x, int c) {
    if (l == r) {
        tp[id] = c;
        if (tp[id] <= 1) cnt[id][tp[id]] = 1, cnt[id][tp[id] ^ 1] = 0;
        else cnt[id][0] = cnt[id][1] = 0;
        mina[id] = cnt[id][1];
        return;
    }
    int mid = (l + r) / 2;
    if (x <= mid) change(id << 1, l, mid, x, c);
    else change(id << 1 | 1, mid + 1, r, x, c);
    update(id);
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= m; i++) scanf("%d", &b[i]);
        sort(b + 1, b + m + 1);
        for (int i = 1; i <= n; i++) p[i] = make_pair(a[i], i);
        sort(p + 1, p + n + 1);
        build(1, 0, n);
        int pl = 1;
        ll ans = 0;
        for (int i = 1; i <= m; i++) {
            while (pl <= n && p[pl].first < b[i]) change(1, 0, n, p[pl].second, 0), pl++;
            if (b[i] != b[i - 1]) {
                for (int j = pl; p[j].first == b[i]; j++) change(1, 0, n, p[j].second, 2);
            }
            ans += mina[1];
        }
        for (int i = 1; i <= n; i++) a[p[i].second] = i;
        for (int i = 1; i <= n; i++) bit::val[i] = 0;
        for (int i = 1; i <= n; i++) {
            ans += i - 1 - bit::ask(a[i] - 1);
            bit::add(a[i], 1);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

6.Conclusion

        这段代码实现了一个算法,其作用是计算给定的数组a和b的某种特定操作的结果。

下面是代码的主要功能和步骤的解释:

1.定义了常量和类型别名:MAXN指定了数组a和p的最大长度,MAXM指定了数组b的最大长度,MAXNODE指定了线段树的最大节点数。ll是long long的别名,pii是pair的别名。
2.声明了全局变量:n和m分别表示数组a和b的长度,a和b分别是待处理的输入数组,cnt用于记录线段树中0和1的个数,mina记录每个节点的最小值,tp记录每个节点的状态(0、1、或2),p用于对数组a进行排序。
3.声明了bit命名空间:定义了val数组和两个函数,用于维护树状数组。
4.定义了update函数:根据左右子树的统计信息更新节点id的统计信息。
5.定义了build函数:递归地构建线段树。当l和r相等时,表示叶节点,根据l的值设置相应的统计信息。否则,计算中间位置mid,递归构建左子树和右子树,并根据子树的统计信息更新当前节点的统计信息。
6.定义了change函数:根据id表示的节点在[l, r]区间内的位置x,改变该位置的状态,并更新相关统计信息。
7.主函数main:先读入测试样例数量T,然后通过循环处理每个样例。

        读入n和m,分别表示数组a和b的长度。
        读入数组a和数组b。
        对数组b进行排序,以备后续二分查找。
        构建线段树,初始化统计信息和节点状态。
        初始化循环变量pl和结果变量ans。
        遍历数组b,对于每个元素b[i],处理满足p[pl].first &lt; b[i]的数组a的元素,将其状态修改为0,并更新统计信息。同时,如果b[i]不等于上一个元素b[i-1],将满足p[j].first == b[i]的数组a的元素状态修改为2,即表示它们不再对结果产生贡献。
        根据线段树的根节点的最小值min_a[1],累加到结果ans中。
        还原数组a的顺序,使得a[i]表示排名为i的元素的位置。
        初始化树状数组val,每个位置初始值为0。
        遍历还原后的数组a,同时用树状数组维护位置的前缀和,计算当前元素的逆序对数,并累加到结果ans中。
        输出结果ans。

        这段代码主要涉及了线段树的构建和维护,以及树状数组的应用,用于高效地处理统计信息和计算逆序对数。其核心思想是通过将数组a中的元素状态化为0、1或2,以及使用线段树和树状数组来高效地统计和计算结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向阳而生__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值