1. 程式人生 > 其它 >H2. Maximum Crossings (Hard Version)_差分樹狀陣列+思維轉化

H2. Maximum Crossings (Hard Version)_差分樹狀陣列+思維轉化

H2. Maximum Crossings (Hard Version)

題目大意:

有兩條平行的線段,點line1[i]和line2[ai]相連。問最多有幾個交點。

思路和程式碼:

今天吃午飯的時候隊裡的神犇傑鍋來跟我炫耀,吹水間跟我說了這個題目。我來補一下。

首先把題目轉化成,[1,i-1]中有多少個點大於等於ai。又考慮到ai的範圍是2e5。

所以只要做一個桶tr,每次判斷一下ai在[1,i-1]中出現了幾次,即直接引用tr[ai]即可。

再把[1,ai]這個範圍裡的tr全部加1,即可維護出[1,i-1]中有多少個數大於等於ai。

而以上維護操作就是一個區間修改單點查詢的問題,可以直接用線段樹

做,但是利用差分樹狀陣列可以更加快樂。

利用差分樹狀陣列就是把區間修改單點查詢轉化成單點修改字首和的過程。

/*
BIT
區間查詢 單點修改 

差分BIT
單點查詢 區間修改 
*/
int n , m , k ; 

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

ll query(int x , vct<ll> &tr){
	ll res = 0 ;
	while(x) res += tr[x] , x -= lowbit(x) ;
	return res ;
}

void add(int x , int det , vct<ll> &tr){
	
	for(int i = x ; i <= n ; i += lowbit(i))
		tr[i] += det ;
}

void solve(){
	cin >> n ;
	vct<int> a(n + 1 , 0) ;
	vct<ll> tr(n + 2 , 0) ;
	rep(i , 1 , n) cin >> a[i] ;
	
	ll ans = 0 ;
	rep(i , 1 , n){
		int num = query(a[i] , tr) ;
		ans += num ;
		add(1 , 1 , tr) ;
		add(a[i] + 1 , -1 , tr) ;
	}
	cout << ans << "\n" ;
	
}//code_by_tyrii 

小結:

這題主要難在如何將“[1,i-1]中大於等於ai的數量”轉化成一個樹狀陣列的問題。

好題!