码迷,mamicode.com
首页 > 其他好文 > 详细

【CF1000F】One Occurrence

时间:2021-06-03 17:43:17      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:turn   clu   return   还需   下标   lin   长度   ons   contest   

题目

题目链接:https://codeforces.com/contest/1000/problem/F
给定一个长度为 \(n\) 序列,\(Q\) 个询问,每次询问给定一个区间 \([l,r]\),如果这个区间里存在只出现一次的数,输出这个数(如果有多个就输出任意一个),没有就输出 \(0\)
\(n,Q\leq 5\times 10^5\)

思路

预处理出 \(\text{pre}[i]\) 表示下标为 \(i\) 的位置前一个和它相同的数是哪一个。
把询问按照 \(r\) 从小到大排序,当确定右端点为 \(r\) 的时候,我们只需要维护每一个数字最后出现的位置(且不超过 \(r\))的最大值即可。线段树一个区间 \([l,r]\) 维护目前已经加入的数中 \(\text{pre}[x]\in [l,r]\)\(x\)。询问区间 \([1,l)\) 的最大值判断是否不小于 \(l\) 即可。
还需要注意对于 \(\text{pre}[x]=0\) 的位置 \(x\),可以维护一个 set 来求下标最大值。
当插入一个下标 \(i\) 的时候需要取消 \(\text{pre}[i]\) 的贡献。
时间复杂度 \(O(Q\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=500010;
int n,Q,a[N],ans[N],pre[N],last[N];
set<int> s;

struct node
{
	int l,r,id;
}b[N];

bool cmp(node x,node y)
{
	return x.r<y.r;
}

struct SegTree
{
	int maxn[N*4];
	
	void update(int x,int l,int r,int k,int v)
	{
		if (l==r) { maxn[x]=v; return; }
		int mid=(l+r)>>1;
		if (k<=mid) update(x*2,l,mid,k,v);
			else update(x*2+1,mid+1,r,k,v);
		maxn[x]=max(maxn[x*2],maxn[x*2+1]);
	}
	
	int query(int x,int l,int r,int ql,int qr)
	{
		if (ql>qr) return 0;
		if (ql<=l && qr>=r) return maxn[x];
		int mid=(l+r)>>1,res=0;
		if (ql<=mid) res=max(res,query(x*2,l,mid,ql,qr));
		if (qr>mid) res=max(res,query(x*2+1,mid+1,r,ql,qr));
		return res;
	}
}seg;

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		pre[i]=last[a[i]]; last[a[i]]=i;
	}
	scanf("%d",&Q);
	for (int i=1;i<=Q;i++)
	{
		scanf("%d%d",&b[i].l,&b[i].r);
		b[i].id=i;
	}
	s.insert(0);
	sort(b+1,b+1+Q,cmp);
	for (int i=1,j=1;i<=Q;i++)
	{
		for (;j<=b[i].r;j++)
			if (pre[j])
			{
				if (!pre[pre[j]]) s.erase(*s.find(pre[j]));
					else seg.update(1,1,n,pre[pre[j]],0);
				seg.update(1,1,n,pre[j],j);
			}
			else s.insert(j);
		int res=max(*(--s.end()),seg.query(1,1,n,1,b[i].l-1));
		if (res>=b[i].l) ans[b[i].id]=a[res];
	}
	for (int i=1;i<=Q;i++) cout<<ans[i]<<"\n";
	return 0;
}

【CF1000F】One Occurrence

标签:turn   clu   return   还需   下标   lin   长度   ons   contest   

原文地址:https://www.cnblogs.com/stoorz/p/14843309.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!