1. 程式人生 > 其它 >CF1042D Petya and Array(cdq分治/資料結構)

CF1042D Petya and Array(cdq分治/資料結構)

題面

有一個長度為 \(n\) 的序列 \(a\) 和一個數 \(t\),求有多少個區間 \([l,r]\) 滿足 \(a_{l}+a_{l+1}+...+a_{r}<t\)\((n\le 2×10^5,|t|\le 2×10^{14},|a_i|\le 10^9)\)

題解

將題目轉化為“求有多少對 \(l,r\) 滿足 \(S_r-S_l<t\)",其中 \(S\) 為字首和,\(l\in [0,n-1],r\in [1,n]\)

法1:CDQ分治

當分治到 \([l,r]\)

  1. 遞迴求解 \([l,mid]\)\([mid+1,r]\)
  2. 此時 \([l,mid]\)\([mid+1,r]\)
    是有序的,用雙指標求出 \([l,r]\) 的答案。
  3. 將區間 \([l,r]\) 排序。
#include<bits/stdc++.h>
#define int long long
const int maxn = 2e5 + 5;
int n, t, a[maxn], S[maxn];
int ans = 0;

void solve(int l, int r) {
	if(l == r) return ;
	int mid = (l + r) >> 1;
	solve(l, mid); solve(mid + 1, r);
	
	int L = l, R = mid + 1;
	while(L <= mid && R <= r) {
		if(S[L] + t <= S[R]) {
			++L;
		}
		else {
			ans += mid - L + 1;
			++R;
		}
	}
	std::sort(S + l, S + r + 1);
}
signed main() {
	std::ios::sync_with_stdio(0); std::cin.tie(0), std::cout.tie(0);
	std::cin >> n >> t;
	for(int i = 1; i <= n; ++i) {
		std::cin >> a[i];
		S[i] = S[i - 1] + a[i];
	}
	solve(0, n);
	std::cout << ans;
		
	return 0;
} 

法二:權值線段樹