Closest Equals

Closest Equals

题目大意

给定一个下标从 \(1 ~ n\) 的序列 \(a\),然后进行 \(m\) 次询问。

每次询问给出一对 \([l,r]\),找到区间中数值相等的且距离最相近的两个数 ai 和 aj,求它们的距离。

换言之找到一组数 \((a_i,a_j)\) 满足

  • \(a_i=a_j\);

  • \(l≤i,j≤r (i≠j)\);

\(|i−j|\) 的最小值,如果区间中不存在相等的两个数,则输出 \(−1\)

思路

首先对于一个数\(x\)来说,如果他出现的位置为 \(x, y, z,(x < y < z)\),那么对答案造成贡献的就只有 \((x,y)\)\((y, z)\)两个区间。
接着对于\((x, y)\)来说,其对所有的满足 \(l \leq x, y \leq r\)\(l ,r\)都会造成贡献。
\((x,y)\)\((l,r)\)表示在二维坐标系上为(图有点丑陋):
https://images.cnblogs.com/cnblogs_com/KeepInCode/1922148/o_220313170829_%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202022-03-14%20010819.jpg
\(l\)为横坐标,\(r\)为纵坐标,在每个点\((x,y)\)\((1, n)\)所围成的区域中的每个点是可以取到答案\(y - x\)的区间\((l,r)\)

并且可以看出\(l\)小的区域是可以取到\(l\)大的区域的答案的,因此我们将每个点\((x, y)\)和每个询问\((l, r)\)预处理出来,并且以\(l\)从大到小排序后遍历。

对于某个\(l\),首先将保存在\(l\)出的点\((x, y)\) 进行处理,我们只需要在纵坐标上维护一个区间最小值的线段树,每次用\(y - x\)更新\((y, n)\)这个区间的值,更新完毕后,再处理这个\(l\)上保存的询问即可,每次询问都直接单点询问答案即可。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5+7;
struct ${
        int l,r,mid,lz,mi;
}tree[N << 2];

void build(int l,int r,int rt = 1) {
        int mid = (l + r) >> 1;
        tree[rt].mid = mid;
        tree[rt].l = l;
        tree[rt].r = r;
        tree[rt].lz = tree[rt].mi = 1e9;
        if (l == r)
                return;
        build(l, mid, rt << 1);
        build(mid + 1, r, rt << 1 | 1);
}
void pushup(int rt) {
        tree[rt].mi = min(tree[rt << 1].mi, tree[rt << 1 | 1].mi);
}
void pushdown(int rt) {
        if (tree[rt].lz != 1e9) {
                tree[rt << 1].lz = min(tree[rt << 1].lz, tree[rt].lz);
                tree[rt << 1].mi = min(tree[rt << 1].mi, tree[rt << 1].lz);
                tree[rt << 1 | 1].lz = min(tree[rt << 1 | 1].lz, tree[rt].lz);
                tree[rt << 1 | 1].mi = min(tree[rt << 1 | 1].mi, tree[rt << 1 | 1].lz);
                tree[rt].lz = 1e9;
        }
}
void change(int l,int r,int x,int rt) {
        if (l <= tree[rt].l && tree[rt].r <= r) {
                tree[rt].mi = min(tree[rt].mi, x);
                tree[rt].lz = min(tree[rt].lz, x);
                return;
        }
        pushdown(rt);
        if (l <= tree[rt].mid) {
                change(l, r, x, rt << 1);
        }
        if (tree[rt].mid < r) {
                change(l, r, x, rt << 1 | 1);
        }
        pushup(rt);
}
int query(int l, int rt) {
        if (tree[rt].l == tree[rt].r) {
                return tree[rt].mi;
        }
        pushdown(rt);
        if (l <= tree[rt].mid)
                return query(l, rt << 1);
        if (tree[rt].mid < l)
                return query(l, rt << 1 | 1);
}

int n, m, a[N];
vector<int>v[N];
struct $${
        int l, r, f, idx;
        bool operator < (const $$ p) const {
                if (l != p.l)
                        return l > p.l;
                else if (f != p.f)
                        return f < p.f;
                else 
                        return r < p.r;
        }
};
void solve() {
        scanf("%d%d", &n, &m);
        map<int,int>mp;
        set<int>s;
        for (int i = 1; i <= n; i++) {
                scanf("%d", &a[i]);
                s.insert(a[i]);
        }
        int cnt = 0;
        for (int i : s) {
                mp[i] = ++cnt;
        }
        for (int i = 1; i <= n; i++) {
                v[mp[a[i]]].push_back(i);
        }
        vector<$$>vv;
        for (int i : s) {
                int pre = 0;
                for (int j : v[mp[i]]) {
                        if (pre) {
                                vv.push_back($${pre, j, 0, 0});
                        }
                        pre = j;
                }
        }
        for (int i = 1; i <= m; i++) {
                int l,r;
                scanf("%d%d", &l,&r);
                vv.push_back($${l, r, 1, i});
        }
        sort(vv.begin(), vv.end());
        build(1, n, 1); 
        vector<int>ans(m + 1);
        for (auto p : vv) {
                if (p.f) {
                        int k = query(p.r, 1); 
                        if (k == 1e9) {
                                ans[p.idx] = -1;
                        } else {
                                ans[p.idx] = k;
                        }
                } else {
                        change(p.r, n, p.r - p.l, 1);
                }
        }
        for (int i = 1; i <= m; i++)
                printf("%d\n", ans[i]);
}

int main() {
        solve();
        return 0;
}
posted @ 2022-03-14 01:15  !^^!  阅读(31)  评论(0编辑  收藏  举报