Closest Equals CodeForces - 522D

题意略 (vjudge上有中文体面)

一道很标准的离线查询问题 可以直观的想到首先要将n个数中相同且距离最近的两个数作为一条线段剥离出来存到结构体当中 这时常规的做法就是用线段树或者树状数组 但是要注意如果直接对线段进行预处理在在线处理每一个查询的数对是比较麻烦的 就说样例1 1 2 3 2 其中一条线段为【3,5】 如果直接把3到5的值都设为2的话 那么出现了【4,5】这样的查询是就会出错 所以需要离线查询可以看到倘若一个查询数对必然要包含一条线段才能更新其计数器 所以这里可以采取排序的方法 将左端大的排在前面 左端相同时优先将查询对放在前面 然后对于每一条线段需要更新时就往后更新最小值 这样就可以保证每次离线查询时得出正确的答案

这里采用树状数组的做法 注意对 1 1 1 1 1 这种样例的处理 还有数组要开得足够大

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <bitset>
#include <vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn=500005;
const int inf=0x3f3f3f3f;
int n,m,a[maxn],b[maxn],tree[maxn],ans[maxn];
vector<int>v[maxn];
struct line
{
    int l,r,id;
    bool operator <(const line temp)const
    {
        if(l>temp.l) return true;
        else if(l==temp.l)
        {
            if(id>temp.id)
            {
                return true;
            }
        }
        return false;
    }
}L[2*maxn];
int lowbit(int x)
{
    return x&-x;
}
int query(int x)
{
    int ret=inf;
    while(x)
    {
        ret=min(ret,tree[x]);
        x-=lowbit(x);
    }
    return ret;
}
void update(int x,int val)
{
    int ret=inf;
    while(x<maxn)
    {
        tree[x]=min(tree[x],val);
        x+=lowbit(x);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<maxn;i++) ans[i]=tree[i]=inf;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    int re_n=unique(b+1,b+1+n)-(b+1);
    for(int i=1;i<=n;i++)
    {
        a[i]=lower_bound(b+1,b+1+re_n,a[i])-b;
        v[a[i]].push_back(i);
    }
    int next=0;
    for(int i=1;i<=re_n;i++)
    {
        for(int j=1;j<v[i].size();j++)
        {
            next++;
            L[next].r=v[i][j];
            L[next].l=v[i][j-1];
            L[next].id=i+m;
        }
    }
    for(int i=1;i<=m;i++)
    {
        next++;
        scanf("%d%d",&L[next].l,&L[next].r);
        L[next].id=i;
    }
    sort(L+1,L+1+next);
    for(int i=1;i<=next;i++)
    {
        if(L[i].id<=m)
        {
            ans[L[i].id]=query(L[i].r);
        }
        else
        {
            update(L[i].r,L[i].r-L[i].l);
        }
    }
    for(int i=1;i<=m;i++)
    {
        if(ans[i]==inf) cout<<-1<<endl;
        else cout<<ans[i]<<endl;
    }
}
/*
5 1
1 1 2 3 2
3 5

10 10
1 1 1 1 1 1 1 1 1 1
1 2
1 3
2 3
4 5
5 6
1 9
1 10
1 5
1 3
1 1
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值