首页 > 其他分享 >洛谷题单指南-二叉堆与树状数组-P1908 逆序对

洛谷题单指南-二叉堆与树状数组-P1908 逆序对

时间:2024-11-18 14:57:47浏览次数:1  
标签:树状 int 洛谷题 P1908 add 数组 逆序

原题链接:https://www.luogu.com.cn/problem/P1908

题意解读:求逆序对,前面介绍过归并排序的做法,参考:https://www.cnblogs.com/jcwy/p/184077,这里介绍树状数组的做法。

解题思路:

设数组a[n]里的整数只包括1~n,显然对于此题,可以通过离散化得到这样的数组。

要计算逆序对,就是要计算对于每一个数,位置靠后且值较小的数有多少个,累加起来即可。

如何统计比每一个数位置靠后且值较小的数的个数?

设b[i]表示值为i的数出现的个数,

可以从后往前遍历a中每一个数,对于每一个遍历到的数a[i],计算b[1] ~ b[a[i] - 1]之和,累加到ans,

然后把a[i]的个数更新b[a[i]]++,如此变可以统计所有的逆序对数量。

问题转化为如何快速计算b的前缀和,已经修改b的值,就可以借助树状数组!

设树状数组tr[N]是b的树状数组,通过sum(a[i] - 1)来计算b[1] ~ b[a[i] - 1]之和,通过add(a[i], 1)来实现b[a[i]]++。

100分代码:

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

typedef long long LL;
const int N = 500005;
int n;
int a[N], b[N], c[N], cnt, tr[N];
map<int, int> h;
LL ans;

int lowbit(int x)
{
    return x & -x;
}

void add(int x, int val)
{
    for(int i = x; i <= n; i += lowbit(i)) tr[i] += val;
}

int sum(int x)
{
    int res = 0;
    for(int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    //去重,离散化
    memcpy(b, a, sizeof(a));
    sort(b + 1, b + n + 1);
    for(int i = 1; i <= n; i++)
    {
        if(b[i] != b[i - 1]) c[++cnt] = b[i], h[c[cnt]] = cnt;
    }
    for(int i = 1; i <= n; i++) a[i] = h[a[i]];

    //逆序对统计
    for(int i = n; i >= 1; i--)
    {
        ans += sum(a[i] - 1);
        add(a[i], 1);
    }
    cout << ans;

    return 0;
}

 

标签:树状,int,洛谷题,P1908,add,数组,逆序
From: https://www.cnblogs.com/jcwy/p/18552254

相关文章

  • 小寄巧——给洛谷题单快速生成一份目录
    以此题单为例,首先我们在浏览器中打开,F12切换到Console,输入document.querySelectorAll(".titlea"),然后复制返回的所有内容,粘贴到VSCode里,内容大致如下:NodeList(15)[a.title.color-default,a.title.color-default,a.title.color-default,a.title.color-default,a.title......
  • 洛谷题单指南-二叉堆与树状数组-P3368 【模板】树状数组 2
    原题链接:https://www.luogu.com.cn/problem/P3368题意解读:树状数组应用-区间修改,单点求值解题思路:设原数组为s[N],其差分数组为a[N]操作一:区间修改要对s[x]~s[y]每个数增加k,相当于对a[x]加k,对a[y+1]减k,O(n)的操作变成了O(1)的操作,利用树状数组tr[N]的add(x,k),add(y+......
  • 洛谷题单指南-二叉堆与树状数组-P3374 【模板】树状数组 1
    原题链接:https://www.luogu.com.cn/problem/P3374题意解读:树状数组模版:单点修改,区间求值。解题思路:树状数组-BinaryIndexTree可以动态维护一组数,可以O(logn)的修改一个数,也可以O(logn)的计算一段区间的和。思考一下朴素做法:如何修改一个数,计算区间和?如果是常规数组,修改操作......
  • 【SSLOJ 3347】动态逆序对
    题目大意给出一个长度为\(n\)的排列\(a\)。每次交换两个数,求逆序对数对\(2\)取模的结果。输入格式第一行一个正整数\(n\)。第二行\(n\)个数,表示给出的排列\(a\)。第三行一个正整数\(q\)。接下来\(q\)行,每行两个正整数,表示交换\(a_i\)和\(a_j\)。输出格式输出......
  • 洛谷题单 算法2-2 常见优化技巧
    洛谷题单算法2-2常见优化技巧单调栈单调栈最经典的应用,就是在一个数列里寻找距离元素最近的比其大/小的元素位置。模板题,寻找每个元素右边第一个比它大的元素下标。stack<int>s;for(inti=n;i>=1;i--){while(s.size()&&a[s.top()]<=a[i])s.pop();f[i]=s.......
  • 洛谷题单指南-二叉堆与树状数组-P1878 舞蹈课
    原题链接:https://www.luogu.com.cn/problem/P1878题意解读:n个男女排列一行,每人舞蹈技术是ai,每次找到相邻男女舞蹈技术差值绝对值最小的一对出列,输出每对出列的人员编号。解题思路:设初始有8人编号为:12345678将12,23,34,45,56,67,78中是男女的配对编号以及a......
  • 题解:「2017 山东一轮集训 Day7」逆序对
    LibreOJ6077前置知识:生成函数、组合数先考虑平方怎么做。\(f_{i,j}\)表示处理了前\(i\)个值,逆序对有\(j\)个。显然可以转移到\(f_{i+1,j},f_{i+1,j+1},f_{i+1,j+2},...,f_{i+1,j+i}\)。然后发现这个东西是个很简单的递推,而且长得很生成函数,于是可以很自然的写成\[1\t......
  • 编写函数:递归求逆序 (Append Code) ★
    Description将输入的一个字符串s逆序输出。编写函数recursive()完成程序:原型:intrecursive();功能:用递归的方法读取输入,并且逆序输出。函数的调用格式见“AppendCode”。InvalidWord(禁用单词)错误:在解决这个题目时,某些关键词是不允许被使用的。如果提交的程序中包含了下......
  • 洛谷题单103数组题解||by红糖
    P1428小鱼比可爱题目描述人比人,气死人;鱼比鱼,难死鱼。小鱼最近参加了一个“比可爱”比赛,比的是每只鱼的可爱程度。参赛的鱼被从左到右排成一排,头都朝向左边,然后每只鱼会得到一个整数数值,表示这只鱼的可爱程度,很显然整数越大,表示这只鱼越可爱,而且任意两只鱼的可爱程度可能一样......
  • 洛谷题单指南-二叉堆与树状数组-P2085 最小函数值
    原题链接:https://www.luogu.com.cn/problem/P2085题意解读:有n个函数,函数中x取值>=1,计算所有函数能得到的值中最小的m个。解题思路:函数中x取值是>=1的整数,因此每个函数的值是f(1),f(2),f(3)....,是一个递增序列,题目本质上是要从n个递增序列中找到前m个最小的数。首先,对所有函数......