CF689D Friends and Subsequences 题解
题目链接:CF689D Friends and Subsequences
题意:
- 给定序列 \(a\) 和序列 \(b\),长度均为 \(n\)。问有多少组 \((l,r)\),满足 \(1\le l\le r\le n\) 且 \(\displaystyle \max_{i=l}^r a_i=\min_{i=l}^r b_i\)
- \(1\le n\le 2\times 10^5\),\(|a_i|,|b_i|\le 10^9\)。
输入格式:
The first line contains only integer \(n\) (\(1\leq n\leq 200000\)).
The second line contains \(n\) integer numbers \(a_{1}, a_{2}, \ldots, a_{n}\) (\(-10^9 \leq a_i \leq 10^9\)) — the sequence \(a\).
The third line contains \(n\) integer numbers \(b_{1}, b_{2}, \ldots, b_{n}\) (\(-10^9 \leq b_i \leq 10^9\)) — the sequence \(b\).
输出格式:
Print the only integer number — the number of occasions the robot will count, thus for how many pairs \(\displaystyle \max _{i=l}^r a_i=\min _{i=l}^r b_i\) is satisfied.
注意到当左端点固定时,\(a\) 最大值减 \(b\) 最小值的差会单调不降。
容易想到这样的做法:枚举合法区间的左端点,然后二分一个右端点。然而这个做法是错的。
假设 \([l,r]\) 是一个极大合法的区间,且区间 \([p,l-1]\) 不合法。而此时 \([p,l]\) 却可能是一个合法区间。
于是考虑枚举左端点 \(l\) ,接着做两个二分,得到以 \(l\) 为左端点的极大合法区间的范围 \([l^{\prime},r^{\prime}]\) ,
则对于任意整数 \(x \in [l^{\prime}, r^{\prime}]\) ,区间 \([l,x]\) 为合法区间,并且 \(l^{\prime}\) 是最左侧的那个,\(r^{\prime}\) 是最右侧的那个。
实现的话,因为不带修改,所以可以用 ST表
解决,线段树二分有空再写吧。
时间复杂度 \(\mathcal{O}(n \log n)\)
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(2e5 + 5))
#define LN 20
int n,res,lg[N],f1[LN][N],f2[LN][N];
int qmax(int l,int r)
{
int k = lg[r - l + 1];
return max(f1[k][l], f1[k][r - (1 << k) + 1]);
}
int qmin(int l,int r)
{
int k = lg[r - l + 1];
return min(f2[k][l], f2[k][r - (1 << k) + 1]);
}
int ql(int i)
{
int l = i, r = n;
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(qmax(i,mid) <= qmin(i,mid)) l = mid;
else r = mid - 1;
}
if(l <= n && qmax(i,l) == qmin(i,l)) return l;
return 0;
}
int qr(int i)
{
int l = i, r = n;
while(l < r)
{
int mid = (l + r) >> 1;
if(qmax(i,mid) >= qmin(i,mid)) r = mid;
else l = mid + 1;
}
if(r > 0 && qmax(i,r) == qmin(i,r)) return r;
return 0;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cin >> n;
for(int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;
for(int i = 1; i <= n; i++) cin >> f1[0][i];
for(int i = 1; i <= n; i++) cin >> f2[0][i];
for(int j = 0; 1 << (j + 1) <= n; j++)
{
int *f = f1[j], *g = f1[j + 1];
for(int i = 1; i + (1 << j) - 1 <= n; i++)
g[i] = max(f[i], f[i + (1 << j)]);
f = f2[j], g = f2[j + 1];
for(int i = 1; i + (1 << j) - 1 <= n; i++)
g[i] = min(f[i], f[i + (1 << j)]);
}
for(int i = 1; i <= n; i++)
{
int l = ql(i), r = qr(i);
if(!l || !r) continue; if(l > r) swap(l,r);
res += (r - l + 1);
}
cout << res << '\n';
return 0;
}