1. 程式人生 > >求逆序數數目(樹狀數組+離散化)

求逆序數數目(樹狀數組+離散化)

string pre ext com pad margin ons style sizeof

404在玩忍者印記(Mark of the Ninja)操縱忍者時遇到這樣一個場景,兩棟大樓之間有許多繩索,從側面看,就像這個樣子:

技術分享

我們的忍者非常有好奇心,他可以觀察到每個繩索的端點在兩棟樓的高度,想知道這些繩索有多少個交點(圖中黑色的點)。他觀察到不會建築上不會有一點上有兩個繩索,並且沒有三條繩索共點。

輸入描述

第一行:整數T,代表有T組數據。 (1 <= T <= 100)

下一行:整數N,代表有N條繩索。 (1 <= N <= 100000)

接下來Na行給出兩個整數A_i, B_i,分別代表繩索端點在左右兩邊大樓的高度。

0 <= A_i,B_i <= 1000000000

輸出描述

Case #x: y

x代表樣例組數,從1開始。

y代表繩索交點數。

樣例輸入

2
3
1 10
5 5
7 7
2
1 1
2 2

樣例輸出

Case #1: 2
Case #2: 0

樹狀數組高效求出逆序對,點的數目少,數值可能很大,所以用了離散化處理
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn= 1e5+7;
int sum[maxn], arr[maxn], k;
struct Edge{ int a, b; bool operator < (const Edge t)const{ if(a != t.a) return a < t.a; return b < t.b; } }edge[maxn]; int lowbit(int x){ return -x & x; } void add(int i, int val){ while(i <= maxn){ sum[i] += val; i += lowbit(i); } }
int Sum(int i){ int s = 0; while(i){ s += sum[i]; i -= lowbit(i); } return s; } int bisearch(int key, int n){ int l = 1, r = n; while(l <= r){ int m = (l + r)/2; if(arr[m] == key) return m; if(arr[m] < key) l = m + 1; else r = m - 1; } // } int main(){ //freopen("in.txt", "r", stdin); int t; scanf("%d", &t); int kase = 1; while(t--){ scanf("%d", &k); for(int i = 0; i < k; i++){ scanf("%d%d", &edge[i].a, &edge[i].b); arr[i+1] = edge[i].b; } sort(arr+1, arr+k+1); int m = 2; for(int i = 2; i < k; i++){ if(arr[i] != arr[i-1]){ arr[m++] = arr[i]; } } sort(arr+1, arr+m+1); sort(edge, edge+k); memset(sum, 0, sizeof(sum)); long long ans = 0; for(int i = 0; i < k; i++){ int lisan = bisearch(edge[i].b, m); add(lisan, 1); ans += Sum(m) - Sum(lisan); //printf("%d\n", lisan); } printf("Case #%d: ", kase++); printf("%lld\n", ans); } return 0; }

求逆序數數目(樹狀數組+離散化)