离线线段树 Codeforces522D Closest Equals

传送门:点击打开链接

题意:n个点告诉你,m次查询,每次查询给l,r,求区间[l,r]里面两个相等的数字的最近的距离是多少。

思路:一般这种没有修改的题,都可以用离线来搞,按照区间右端点排序。然后各个点的值比较大,把它离散一下。

用pre[i]维护上一个节点的位置,然后在线段树中,一个节点维护的是以这个节点作为两个相等的数字的左边那个,最小距离是多少。每次移动右端点时,都更新一下A[pre[A[i]]]]的值,然后询问直接线段树就可以搞定了。

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

const int MX = 5e5 + 5;
const int INF = 0x3f3f3f3f;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int MIN[MX << 2];
void push_up(int rt) {
    MIN[rt] = min(MIN[rt << 1], MIN[rt << 1 | 1]);
}
void update(int x, int d, int l, int r, int rt) {
    if(l == r) {
        MIN[rt] = min(MIN[rt], d);
        return;
    }
    int m = (l + r) >> 1;
    if(x <= m) update(x, d, lson);
    else update(x, d, rson);
    push_up(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        return MIN[rt];
    }
    int m = (l + r) >> 1, ret = INF;
    if(L <= m) ret = min(ret, query(L, R, lson));
    if(R > m) ret = min(ret, query(L, R, rson));
    return ret;
}

struct Que {
    int l, r, id;
    bool operator<(const Que &P) const {
        return r < P.r;
    }
} Q[MX];

int pre[MX], A[MX], B[MX], ans[MX];

int main() {
    int n, m; //FIN;
    while(~scanf("%d%d", &n, &m)) {
        memset(MIN, INF, sizeof(MIN));
        memset(pre, 0, sizeof(pre));
        for(int i = 1; i <= n; i++) {
            scanf("%d", &B[i]);
            A[i] = B[i];
        }
        sort(B + 1, B + 1 + n);
        int rear = unique(B + 1, B + 1 + n) - B - 1;
        for(int i = 1; i <= n; i++) {
            A[i] = lower_bound(B + 1, B + 1 + n, A[i]) - B;
        }
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &Q[i].l, &Q[i].r);
            Q[i].id = i;
        }
        sort(Q + 1, Q + 1 + m);

        for(int i = 1, c = 1; i <= n; i++) {
            if(pre[A[i]]) update(pre[A[i]], i - pre[A[i]], 1, n, 1);
            while(c <= m && i == Q[c].r) {
                int Min = query(Q[c].l, Q[c].r, 1, n, 1);
                ans[Q[c++].id] = Min == INF ? -1 : Min;
            }
            pre[A[i]] = i;
        }

        for(int i = 1; i <= m; i++) {
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值