逆序対的另外一種解法是歸併排序
下面兩題的離散化方法會得到不同的陣列!!
關於逆序対
已知陣列的逆序対數目=n,則將陣列中相鄰元素交換n次即可得有序陣列
題目:方法一(5.05s)算出給定的一段正整數序列中逆序對的數目,序列中可能有重複數字。
sort()、unique()、lower_bound()三部曲,得到as[i]表示a[i]是第as[i]小的數字
fo
(i,0
,n)inn
(a[i]
),b[i]
=a[i]
;sort
(b,b+n)
;int l=
unique
(b,b+n)
-b; \\去重,l為不重複元素個數,執行後b[
:l]內都為不重複元素
fo(i,
0,n)
as[i+1]
=lower_bound
(b,b+l,a[i]
)-b+
1; \\二分求a[i]排第幾,+
1是因為b[
]從0開始
排序前a=12, 36, 55, 36, -10
b=12, 36, 55, 36, -10
去重後l=4
b=-10, 12, 36, 55
二分後as=2, 3, 4, 3, 1
as[i]表示a[i]是第as[i]小的數字,如as[1]=2表示a[1]是第2小的數字
有點像大小關係的一種對映,這樣可以把as[i]當做陣列的下標,既能節省空間,還能防止負數作為下標
#include
#define fo(i,a,b) for(int i=a;i#define lowbit(i) ((i)&-(i))
using
namespace std;
inline
void
inn(
int& x)
while
(ch >=
'0'&& ch <=
'9')
x *= f;
}const
int n=5*
1e5+5;
int tr[n]
,n,m,a[n]
,b[n]
;long
long ans;
inline
void
add(
int x,
int k)
}inline
long
long
sum(
int x)
return num;
}int
main()
cout
}
方法二(2.47s)
結構體+sort+手動去重
所得as[i]表示a[i]是第as[i]小的數字,同方法一
#include
#define lowtr(i) ((i)&-(i))
using
namespace std;
inline
void
inn(
int& x)
while
(ch >=
'0'&& ch <=
'9')
x *= f;
}const
int n=5*
1e5+5;
struct numbera[n]
;int n,as[n]
,tr[n]
;bool
cmp(number a,number b)
inline
void
add(
int i,
int k)
inline
intsum
(int i)
intmain()
cout
}
題目:由σ[(ai-bi)2] = σ(ai2-2 * ai * bi + bi2) ,故求σ(2 * ai * bi)最大即可兩盒火柴,每盒裝有 n 根火柴
每盒中的火柴各自排成一列, 同一列火柴的高度互不相同
兩列火柴之間的距離定義為:∑(a_i-b_i)^2
每列火柴中相鄰兩根火柴的位置可以交換,為兩列火柴之間的距離最小,最少交換多少次
而順序之乘》=亂序之乘(兩陣列同為公升序or降序時σ(ai*bi)最大)
所以先將兩列火柴存入分別陣列a、b,把陣列離散化後得到陣列as、bn,as[i]表示第i小的數字是a[as[i]]
由於陣列中元素各不相同,可以用
fo
(i,1
,n+1
)inn
(a[i]
),as[i]
=i;sort
(as+
1,as+
1+n,cmp1)
;bool
cmp1
(int x,
int y)
進行排序
例如:得到陣列as、bn後,通過fo(i,1,n+1) re[as[i]]=bn[i];確定對應關係,再計算re中的逆序対即為交換次數排序前a=12, 55, 36, -10
as=1, 2, 3, 4
排序後a=12, 55, 36, -10
as=4, 1, 3, 2
as[i]表示第i小的數字是a[as[i]],比如as[1]=4表示第1小的數字是a[4]
有點像大小關係的一種對映,這樣可以把as[i]當做陣列的下標,既能節省空間,還能防止負數作為下標
原因是已知陣列的逆序対數目=n,則將陣列中相鄰元素交換n次即可得有序陣列
#include
#define fo(i,a,b) for(int i=a;iusing
namespace std;
typedef
long
long ll;
inline
void
inn(
int& x)
while
(ch >=
'0'&& ch <=
'9')
x *= f;
}const
int n=
1e5+5;
int n,a[n]
,b[n]
,as[n]
,bn[n]
,tr[n]
,re[n]
;ll ans;
bool
cmp1
(int x,
int y)
bool
cmp2
(int x,
int y)
inline
void
add(
int x)
inline ll sum
(int x)
intmain()
printf
("%lld\n"
,ans)
;return0;
}
另附一題
神奇的字串-樹狀陣列
對兩個只包含字母的長度為n的字串s1,s2執行m次操作0 l r 代表 詢問[ l , r ] 這個區間配對的個數
1 id p c 如果id 是1,代表把s1字串p位置置為c,如果id 是2,代表把s2字串p位置置為c
#include
#define fo(i,a,b) for(int i=a;i#define lowbit(i) ((i)&-(i))
using
namespace std;
inline
void
inn(
int& x)
while
(ch >=
'0'&& ch <=
'9')
x *= f;
}const
int n=5*
1e5+5;
int tr[n]
,n,m;
inline
void
add(
int x,
int k)
}inline
intsum
(int x)
return num;
}int
main()
else
printf
("%d\n"
,sum
(y)-
sum(x-1)
);}}
return0;
}
詳解樹狀陣列三種模型
首先說明下 最後的最大值模型的 沒有測試,不過應該是沒問題的。其它三個更新求和的模型的 借鑑於網上的各個博文,應該是沒問題的。其中前兩個模型的 已測試無誤。樹狀陣列與線段樹在思想上很類似的一種資料結構,它比線段樹更簡潔,但它的適用範圍也小了些。提供一篇博文,詳解樹狀陣列的 樹狀陣列是乙個可以高效的進...
樹狀陣列的三種模式
我們在這之前已經了解過了lowbit的概念,還有對於樹狀陣列的基本的認識了,然後,再學習樹狀陣列的基礎用法。樹狀陣列主要有三種型別,從簡單到複雜。依次是修改點,求區間和 修改區間求點,還有最複雜的修改區間,求區間。最簡單的第一種模型 int lowbit int x void add int x,i...
樹狀陣列區間求和三種模型
樹狀陣列在區間求和問題上有大用,其三種複雜度都比線段樹要低很多 有關區間求和的問題主要有以下三個模型 以下設a 1.n 為乙個長為n的序列,初始值為全0 1 改點求段 型,即對於序列a有以下操作 修改操作 將a x 的值加上c 求和操作 求此時a l.r 的和。這是最容易的模型,不需要任何輔助陣列。...