讀完題目,你的第一想法肯定是直接暴力就能過了。實際上在看完資料之後。。。qaq。好吧,肯定不能暴力,那
麼現在就要去尋找它的特徵。根據它的特徵,我們可以分析出要用線段樹去做這道題。那麼當我們確定這個演算法時,我
來的順序再排回來,然後根據每乙個數的大小對號入座,在入座的過程中我們計算在這個葉子節點的右邊有多少個已經
入座的元素,這時候就體現出來了線段樹的便捷:查詢效率為o(log n) 級別。然後使用sum分別記錄,最後輸出sum。
/*
id: erictian2018
task:
lang: c++
*/#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0x7ffffff
#define ll long long
//#include
//#include
using
namespace std;
/*輸入:
65 4 2 5 3 1
輸出:*/
ll scan()
for(
; ch>=
'0'&&ch<=
'9'; ch=
getchar()
) x=x*
10+ch-
'0';if(
!flag)
return x;
return
-x;}
ll n;
struct nodetree[
2000010];
ll sum;
/求有多少個逆序對
struct sta[
500100];
// bool
cmp1
(st a,st b)
// bool
cmp2
(st a,st b)
// void
build
(ll l,ll r,ll k)
// ll ask
(ll l,ll r,ll k)
// void
change
(ll l,ll r,ll k)
ll mid=
(tree[k]
.l+tree[k]
.r)/2;
if(l<=mid)
change
(l,r,k*2)
;if(r>mid)
change
(l,r,k*2+
1); tree[k]
.cnt=tree[k*2]
.cnt+tree[k*2+
1].cnt;
}int
main()
//從小到大排序 如果有相同的數則下標較小的排在前面
sort
(a+1
,a+n+
1,cmp1)
;for
(ll i=
1;i<=n;i++
) a[i]
.rank=i;
//根據order的下標再排回來
sort
(a+1
,a+n+
1,cmp2)
;build(1
,n,1);
for(ll i=
1;i<=n;i++
)change
(a[i]
.rank,a[i]
.rank,1)
;cout << sum << endl;
return0;
}
洛谷P1908 逆序對(線段樹解法)
貓貓tom和小老鼠jerry最近又較量上了,但是畢竟都是成年人,他們已經不喜歡再玩那種你追我趕的遊戲,現在他們喜歡玩統計。最近,tom老貓查閱到乙個人類稱之為 逆序對 的東西,這東西是這樣定義的 對於給定的一段正整數序列,逆序對就是序列中ai aj且i第一行,乙個數n,表示序列中有n個數。第二行n個...
P1908 逆序對 題解
原題鏈結 貓貓 tom 和小老鼠 jerry 最近又較量上了,但是畢竟都是成年人,他們已經不喜歡再玩那種你追我趕的遊戲,現在他們喜歡玩統計。最近,tom 老貓查閱到乙個人類稱之為 逆序對 的東西,這東西是這樣定義的 對於給定的一段正整數序列,逆序對就是序列中a i aj a i a j ai aj ...
洛谷 P1908 逆序對(線段樹區間求和 離散化)
逆序對就是序列中 ai aj且i用乙個flag陣列標記哪些數字已經放入陣列中,用線段樹求flag的字首和,求放入的數字前已經放入了多少個比他小的數字。include using namespace std define int long long define ios ios sync with s...