zoukankan      html  css  js  c++  java
  • 【做题笔记】洛谷P1908逆序对

    树状数组的奇技淫巧(雾)

    听说此题可以用线段树乱搞?

    反正我不会/xyx

    然后此题树状数组思路极其清晰,老少皆宜

    题目大意

    (a_i)(a_j) 成逆序对当且仅当 (i<j)(a_i>a_j)
    现给出一个长度为 (n) 的序列 (a) ,问此序列珂构成多少个逆序对。

    solution

    (a) 的值域上建立树状数组。

    首先倒序扫描 (a) ,然后使答案 (ans) 加上 ( ext{ask}(a_i-1))。然后执行 ( ext{add}(a_i,1))

    其中 ask(x) 表示查询 x 的前缀和,add(x,v) 表示把 x 的位置+v。

    这样做为啥是对的呢?首先了解这样一个东西:

    • (t_{val}) 表示 val 在序列 a 中出现的次数,那么把 [l,r] 内 t 的值累加,得到的就是 a 序列中值域在 [l,r] 内的数的个数。

    举个栗子:

    3hO2GV.png

    那么回到本题,由于是倒序扫描,那么扫描到 (i) 时扫描的也就是“ (a_i) 在序列之后的那些数出现的个数”,能够保证 (i<j)。放个图:

    3hvkDg.png

    同时,由于查询的是 (a_{i}-1) 的前缀和,也就保证了查询发现的数一定保证 (a_i>a_j)

    累计完答案后,再把树状数组中代表 (a_i) 的值加一,代表 (a_i) 又出现了一次,类似于上边说的更新 t 数组。

    整个一套过程下来,完美解决了这个操作。

    注意到 (a_i) 的数值很大,所以需要离散化。

    然后这题离散化时不需要去重。不需要考虑重复元素可能带来的影响:因为 lower_bound 是查找大于等于 x 的第一个位置,那么相同的数就会得到一个相同的排名。

    参考代码

    #include <iostream>
    #include <stdio.h>
    #include <algorithm>
    #define lowbit(x) x & -x
    
    using namespace std;
    
    int n;
    long long ans,a[5*500005],c[5*500005],b[5*500005];
    
    inline void add(int x,int v)
    {
    	for(int i=x;i<=n;i+=lowbit(i)) c[i]+=v;
    }
    
    inline int ask(int x)
    {
    	long long ans=0;
    	for(int i=x;i;i-=lowbit(i)) ans+=c[i];
    	return ans;
    }
    
    inline int read()
    {
    	int s=0,w=1; char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') s=s*10+ch-'0' , ch=getchar();
    	return s*w;
    }
    
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;i++) a[i]=b[i]=read();
    	sort(b+1,b+n+1);
    	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+n+1,a[i])-b;
    	for(int i=n;i;i--)
    	{
    		ans+=ask(a[i]-1);
    		add(a[i],1);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    操作系统的发展史
    多线程的些许理解(平台x86,具体考虑linux,windows)
    C++ 11 智能指针
    C++虚函数和纯虚函数
    Qt之excel 操作使用说明
    查找之二叉排序树
    图的一些总结
    树的一些总结
    直接插入排序
    冒泡和选择排序
  • 原文地址:https://www.cnblogs.com/BlueInRed/p/12404511.html
Copyright © 2011-2022 走看看