标签:时间 query set lse 个数 stream 序列 end tps
传送门
很棒的题。
有两个序列a和b,长度都为n,对于a序列需要知道区间的最大值,对于b序列需要知道区间的最小值
求出符合式子
\(max_{i = l}^ra_i = min_{i = l}^rb_i\)
的所有区间个数。
方法很简单,用st表分别维护a序列的最大值的b序列的最小值,明显,a序列的st表是一个递增函数,b序列的st表是一个递减函数
令a序列的st表减去b序列的st表,那么这个值也是递增的,如果说,值是0,那么久满足题目的情况。
那么遍历左区间,进行二分,用st表\(O(1)\)查询找到0最后一次出现的位置和第一次出现的位置,那么答案就是[左区间, 右区间2 - 右区间1 + 1],都是满足情况的
时间复杂度\(O(nlogn)\)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define ll long long
using namespace std;
const int N = 2e5 + 5;
int a[N], b[N], n, k;
int MAX[N][20], MIN[N][20];
void init(){
memset(MIN, 0x3f, sizeof(MIN));
memset(MAX, 0, sizeof(MAX));
for(int i = 1; i <= n; i++){
MAX[i][0] = a[i];
MIN[i][0] = b[i];
}
for(int j = 1; j <= 20; j++)
for(int i = 1; i + (1 << j) - 1 <= n; i++){
MIN[i][j] = min(MIN[i][j - 1], MIN[i + (1 << (j - 1))][j - 1]);
MAX[i][j] = max(MAX[i][j - 1], MAX[i + (1 << (j - 1))][j - 1]);
}
}
int Query(int l, int r){
int k = log2(r - l + 1);
return max(MAX[l][k], MAX[r - (1 << k) + 1][k]) - min(MIN[l][k], MIN[r - (1 << k) + 1][k]);
}
void solve(){
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i++)
scanf("%d", &b[i]);
ll ans = 0;
init();
for(int i = 1; i <= n; i++){
int l = i, r = n, mid;
while(l <= r){
mid = (l + r) >> 1;
int now = Query(i, mid);
if(now > 0) r = mid - 1;
else l = mid + 1;
}
ans += r - i + 1;//[i, r] 都是 ≤ 0的
l = i, r = n;
while(l <= r){
mid = (l + r) >> 1;
int now = Query(i, mid);
if(now < 0) l = mid + 1;
else r = mid - 1;
}
ans -= r - i + 1;//[i, r] 都是 ≥ 0的
}
printf("%lld\n", ans);
}
int main(){
solve();
return 0;
}
Friends and Subsequences - 二分 + ST表
标签:时间 query set lse 个数 stream 序列 end tps
原文地址:https://www.cnblogs.com/Emcikem/p/13199252.html