---
# System prepended metadata

title: 每個人都需要一個機器貓朋友
tags: [CP]

---

---
tags: CP
---

# 每個人都需要一個機器貓朋友
> reference: NHDK Moon Festival Ten Point Round 2021

在 22 世紀，哆啦A夢是日本警視廳的警視總監，他奉命要調查在太平洋第7島鏈上面的勢力，進行武力分析。

哆啦A夢派出了小哆啦去調查島鏈上面的小島，共 $N$ 個小島，並且對每個小島進行武力分析，得知每個小島的武力值。

這些小島分成兩種派系，一派是支持大雄、一派是支持胖虎，哆啦A夢為了保護大雄避免胖虎的欺負，所以想先分析島鏈上有多少個區間，火拼時大雄會輸。

區間火拼：
則計算區間中大雄派的武力值總和與胖虎派武力值總和，若胖虎派武力值總和大於大雄派武力值總和則大雄派輸。

![](https://i.imgur.com/D1ig2N5.png)

「我不在的時候你能夠好好照顧自己嗎？」哆啦 A夢邊生氣邊流淚地問大雄
# Input
只有一組資料
第一行為一個正整數 $N$ ($1 \leq N \leq 2 \cdot10^5$)，代表島鏈上面的小島數量。
第二行共有 $N$ 個整數 $a_i$ ($1 \leq |a_i| \leq 10^5$)，$|a_i|$為小島的武力值，當 $a_i > 0$ 則為大雄派 ，反之則為胖虎派。

# Output
輸出一個整數，代表島鏈上有多少個區間，火拼時大雄派會輸。

# Sample
Input1:
```
5
3 4 5 6 7
```
Output1:
```
0
```
Input2:
```
5
1021 -5009 1516 -8002 -6311
```
Output2:
```
13
```
# 範例說明

在第一個範例中，小島都是支持大雄，所以大雄沒有輸。
在第二個範例中，共有13個區間大雄會輸，分別為：
$[2, 2]$, $[4, 4]$, $[5, 5]$, $[1, 2]$
$[2, 3]$, $[3, 4]$, $[4, 5]$, $[1, 3]$
$[2, 4]$, $[3, 5]$, $[1, 4]$, $[2, 5]$, $[1, 5]$
以區間 $[1, 4]$ 為例，支持大雄的武力為$1021+1516=2537$、支持胖虎的武力為$5009+8002=13011$，所以這個區間大雄輸。
# Hint
:::spoiler
區間和可視為兩個前綴和相減。
:::



# 題解
:::spoiler
首先，本題目是在找 區間和$\leq 0$ 的個數，如果直接枚舉L與R，時間複雜度為 $O(N^3)$。
使用前綴和加速計算區間和，時間複雜度是 $O(N^2)$。

考慮到一個問題，區間和就是兩個前綴和相減，也就是尋找兩個前綴和，前面的前綴和大於後面的前綴和時，此對應的區間和就是$<0$，當我們將問題思考到這邊的時候，就完成了這題的要求。
前綴和的模反元素數量就是解。
:::

:::spoiler 解法1
```cpp=
#include <bits/stdc++.h>
#define pb push_back
#define Int long long
using namespace std;

Int invpair(vector<Int> &v, int l, int r) {
	if(l == r) return 0;
	int m = (l+r)/2;
	Int res = invpair(v, l, m) + invpair(v, m+1, r);
	vector<Int> tmp;
	for(int i = l, j = m+1; i <= m || j <= r; ) {
		if(i <= m && (j > r || v[i] <= v[j])) {
			tmp.pb(v[i++]);
			res += (j-m-1);
		}
		else tmp.pb(v[j++]);
	}
	for(auto it: tmp) v[l] = it, l++;
	return res;
}

void solve(){
	int n;
	cin >> n;
	vector<Int> A(n), B{0};
	for(auto& it: A) cin >> it;
	for(auto it: A) B.pb(B.back()+it); //len(B) == n+1
	Int ans = invpair(B, 0, n); //[L, R]
	cout << ans << endl;
}
int main(){
	ios::sync_with_stdio(0); cin.tie(0);

	int t=1;
	//cin >> t;
	while(t--) solve();
	return 0;
}
```
:::


:::spoiler 解法2
```cpp=
#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define add insert
#define Int long long
#define pi acosl(-1)
#define MEM(x) memset(x,0,sizeof(x))
#define x first
#define y second
using namespace std;

struct BIT {
	vector<Int> A;
	int n;
	BIT(int _n) {
		n=_n;
		A.resize(n+1);
	}

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

	void update(int idx, Int v) {
		for(int i = idx+1; i <= n; i += lowbit(i)) A[i] += v;
	}

	Int query(int idx)
	{
		Int res = 0;
		for(int i = idx+1; i; i -= lowbit(i)) res += A[i];
		return res;
	}
};


void solve(){
	int n; cin >> n;
	vector<Int> A(n), B{0}, Buni;
	for(auto& it: A) cin >> it;
	for(auto it: A) B.pb(B.back() + it);
	Buni = B;
	sort(Buni.begin(), Buni.end());
	Buni.erase(unique(Buni.begin(), Buni.end()), Buni.end());


	//BIT
	BIT T1(Buni.size());
	Int ans = 0;
	for(int i = 0; i < B.size(); i++) {
		int idx = lower_bound(Buni.begin(), Buni.end(), B[i]) - Buni.begin();
		Int cnt = i - T1.query(idx);
		ans += cnt;
		T1.update(idx, 1LL);
	}
	cout << ans << endl;


}
int main(){
	ios::sync_with_stdio(0); cin.tie(0);

	int t=1;
	//cin >> t;
	while(t--) solve();
	return 0;
}
```
:::