cf522 D. Closest Equals(st表、区间)
作者:互联网
题意:
给定数组,m次查询 L,R,输出区间内相等数对的最小距离。若L到R中没有相等数则输出-1
\(n,m\le 5e5, |a_i|\le 1e9\)
思路:
按相等的数找出不超过n-1个区间,问题变为找 \([L,R]\) 中的最小区间。
若区间A包含区间B,则区间B更优,区间A就没有存在的必要了。最终得到一列左端点严格递增,右端点也严格递增的区间
对于一次询问,二分找含于 \([L,R]\) 的序号最小的区间(序号 \(pl\)),二分找序号最大的 \(pr\)。在区间列 \(pl\cdots pr\) 中用st表找最小值
const int N = 5e5 + 5;
int n, m, a[N], l[N], r[N], idx;
map<int, int> last; //记录每个数最后出现的位置,反正st表预处理也要log
int f[N][20];
void initST(int n)
{
for(int i = 1; i <= n; i++) f[i][0] = r[i] - l[i];
int t = log(n) / log(2) + 1;
for(int j = 1; j < t; j++)
for(int i = 1; i <= n - (1<<j) + 1; i++)
f[i][j] = min(f[i][j-1], f[i + (1<<(j-1))][j-1]);
}
int ask(int l, int r)
{
int k = log(r - l + 1) / log(2);
return min(f[l][k], f[r - (1<<k) + 1][k]);
}
main()
{
iofast;
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = n; i; i--)
{
if(last[a[i]] && (!idx || r[idx] > last[a[i]]))
l[++idx] = i, r[idx] = last[a[i]]; //新区间
last[a[i]] = i;
}
reverse(l + 1, l + 1 + idx), reverse(r + 1, r + 1 + idx);
initST(idx);
while(m--)
{
int L, R; cin >> L >> R;
int lp = lower_bound(l + 1, l + 1 + idx, L) - l;
int rp = upper_bound(r + 1, r + 1 + idx, R) - r - 1;
if(lp > rp) {cout << -1 << endl; continue; }
cout << ask(lp, rp) << endl;
}
}
标签:last,Closest,idx,int,Equals,st,序号,区间,cf522 来源: https://www.cnblogs.com/wushansinger/p/15984851.html