宝石专家

宝石专家

题目描述

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]));
	}
}
posted @ 2019-10-30 14:56  dgklr  阅读(692)  评论(1编辑  收藏  举报