其他分享
首页 > 其他分享> > cf522 D. Closest Equals(st表、区间)

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