宝石专家
题目描述
Jim是一位宝石收藏品行家,在他的收藏室里保存着许多珍贵的宝石,磷叶石、钻石、摩根石、透绿柱石….,已知Jim有n个宝石,现在他将这n个宝石从1到n排开编号从1到n。Jim发现他所有的宝石中竟然有不少是完全相同的的,我们规定每个宝石都有一个特征值ai,当两个宝石特征值相等时及认为两个宝石相同。Jim发现两个相同的宝石离得越接近越明显。Jim现在有m个问题,他想问你在.编号l到r这一区间里的所有宝石中,两个相同宝石的最近距离是多少,(两个宝石的距离是它们编号的绝对值之差)。
保证 l < r ,对于 ax和ay 若ax=ay 它们的距离为|x-y|。
题意
就是询问有许多线段,每一个线段有权值,询问在区间[l,r]中线段的最小权值。
solution
把每一个线段与询问离线并按左排序,用2-pointer从大向小扫,保证对于询问时所有的线段是合法的。
然后使用线段树,询问 [0,r] 之间的最小值即可。
#include<bits/stdc++.h> #define L first #define R second using namespace std; int n; int a[200100]; struct sgt{ int val; int l, r; }d[200100 << 2]; pair <int,int> p[200100]; int pl; map <int,int> t; int ans[200100]; int q; struct qry{ int id; int l, r; bool operator < (qry t){ return l < t.l; } }st[200100]; void build(int x,int l,int r){ d[x].l = l, d[x].r = r; d[x].val = 0x3f3f3f3f; if (l == r) return; build(x<<1,l,(l+r)/2); build(x<<1|1,(l+r)/2+1,r); } void insert(int x,int p,int val){ d[x].val = min(val, d[x].val); if (d[x].l == d[x].r) return; if (p <= d[x<<1].r) insert(x<<1,p,val); else insert(x<<1|1,p,val); } int query(int x,int p){ if (d[x].l == d[x].r) return d[x].val; if (p <= d[x<<1].r) return query(x<<1,p); else return min(d[x<<1].val, query(x<<1|1,p)); } int main(){ cin >> n >> q; for (int i=1;i<=n;i++){ scanf("%d", a+i); if (t.count(a[i])) p[++pl].L = t[a[i]], p[pl].R = i, t[a[i]] = i; else t[a[i]] = i; } for (int i=1;i<=q;i++){ st[i].id = i; scanf("%d%d",&st[i].l,&st[i].r); } sort(p+1,p+pl+1); sort(st+1,st+q+1); int pl1 = pl; int pl2 = q; build(1,1,n); while (pl2 > 0){ while (p[pl1].L >= st[pl2].l) insert(1,p[pl1].R,p[pl1].R-p[pl1].L), pl1--; ans[st[pl2].id] = query(1,st[pl2].r); pl2 --; } for (int i=1;i<=q;i++){ printf("%d\n",(ans[i]==0x3f3f3f3f?-1:ans[i])); } }