题目链接
题解:
如果一段区间它满足
m
a
x
(
l
,
r
)
≤
⌊
s
u
m
(
l
,
r
)
/
2
⌋
max(l, r)\leq \lfloor sum(l, r)/2\rfloor
max(l,r)≤⌊sum(l,r)/2⌋,则代表这个区间符合要求。
那我们就可以对这个区间进行分治,分为最大值左边的区间和最大值右边的区间。那么包括最大值的区间怎么办呢?我们可以枚举长度较小的那个区间的值作为一个端点,二分查找另外一个区间的值作为另外一个端点,计算包含最大值并且符合条件的区间个数。例如最大值左边的区间长度比最大值右边的区间长度大,那就枚举左边的区间作为左端点
l
l
l ,然后二分查找右边符合条件的最左的右端点
r
r
r ,假设区间右端点为
R
R
R,则答案就是
R
−
r
+
1
R-r+1
R−r+1。接着继续分治即可。
查询区间最大值即 RMQ 可以用 ST表解决(注意空间不要开太大,会T)。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<ll, int>
#define debug(x) cout << (#x) << ": " << (x) << " "
#define fastio ios::sync_with_stdio(false), cin.tie(0)
const ull mod = 1e9 + 7;
const int M = 15 + 10;
const int N = 300000 + 10;
int t;
int n, a[N];
ll sum[N];
int lg2[N], id[N][M];
inline void ST_pre()
{
for(int i = 1; i <= n; i ++) { id[i][0] = i; }
for(int j = 1; j <= lg2[n]; j ++) {
for(int i = 1; i <= n - (1<<j) + 1; i ++) {
if(a[id[i][j - 1]] > a[id[i+(1<<(j-1))][j-1]]) {
id[i][j] = id[i][j - 1];
} else {
id[i][j] = id[i+(1<<(j-1))][j-1];
}
}
}
}
inline int ST_query(int l, int r)
{
int k = lg2[r - l + 1];
if(a[id[l][k]] > a[id[r-(1<<k)+1][k]]) {
return id[l][k];
}
return id[r-(1<<k)+1][k];
}
ll deal(int L, int R)
{
if(L >= R) return 0;
int k = ST_query(L, R);
ll ans = 0, mx = a[k];
if(k - L < R - k) {
for(int i = L; i <= k; i ++) {
int l = k, r = R;
if(mx > (sum[r] - sum[i - 1]) >> 1) break;
while(l < r) {
int mid = (l + r) >> 1;
if(mx <= (sum[mid] - sum[i - 1]) >> 1) r = mid;
else l = mid + 1;
}
ans += R - l + 1;
}
} else {
for(int i = R; i >= k; i --) {
int l = L, r = k;
if(mx > (sum[i] - sum[L - 1]) >> 1) break;
while(l < r) {
int mid = (l + r + 1) >> 1;
if(mx <= (sum[i] - sum[mid - 1]) >> 1) l = mid;
else r = mid - 1;
}
ans += r - L + 1;
}
}
ans += deal(L, k - 1);
ans += deal(k + 1, R);
return ans;
}
signed main()
{
for(int i = 1; i < N; i ++) { lg2[i] = log2(i); }
scanf("%d", &t);
while(t --) {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
ST_pre();
printf("%lld\n", deal(1, n));
}
return 0;
}
/*
Rejoicing in hope, patient in tribulation.
*/
/*
,----------------, ,---------,
,-----------------------, ," ,"|
," ,"| ," ," |
+-----------------------+ | ," ," |
| .-----------------. | | +---------+ |
| | | | | | -==----`| |
| | | | | | | |
| | Accepted _ | | |/----|`---= | |
| | | | | ,/|==== OOO | ;
| | | | | // |(((( [33]| ,"
| `-----------------` |," .//| |(((( | ,"
+-----------------------+ // | | |,"
/_)______________(_/ //` | +---------+
___________________________/___ `,
/ oooooooooooooooo .o. oooo /, \,"-----------
/ ==ooooooooooooooo==.o. ooo= // ,`\--{)B ,"
/_==__==========__==_ooo__ooo=_/` /___________,"
*/