牛客 - 牛牛的mex(主席树/思维)

题目链接:点击查看

题目大意:给出一个长度为 n 的排列,再给出 m 次询问,每次询问需要回答区间 [ l , r ] 的 mex

题目分析:算是一道比较经典的题目了吧,先说一般做法,一般做法是 nlogn 的主席树,或者离线线段树,或者是 nsqrt( n ) 的莫队,这里我选择了比较好理解的主席树存一下,主席树的话就是每一个版本的线段树储存一下 [ 1 , i ] 中每个数字最后一次出现的位置,这样每次查询 [ l , r ] ,只需要在第 r 个版本的线段树中查询最小的那个没有出现的数字即可

而这个题目给的恰好是一个 n 的排列,也就是任意两个数都互不相同,这样就可以稍微思考一下优化为 O( n ) 的了,可以从前到后以及从后到前维护两个数组,mmin1 代表的是前缀最小值,mmin2 代表的是后缀最小值,每次对于 [ l , r ] 的查询来说,mmin1[ l - 1 ] 和 mmin2[ r + 1 ] 的最小值就是答案了,想一下是不是非常巧妙

代码:

主席树

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
  
typedef long long LL;
  
typedef unsigned long long ull;
  
const int inf=0x3f3f3f3f;

const int N=1e5+100;

struct Node
{
	int l,r;
	int sum;
}tree[N*20];

int cnt,root[N];

void init()
{
	root[0]=0;
	tree[0].l=tree[0].r=tree[0].sum=0;
	cnt=1;
}

void update(int num,int &k,int l,int r)
{
	tree[cnt++]=tree[k];
	k=cnt-1;
	tree[k].sum++;
	if(l==r)
		return;
	int mid=l+r>>1;
	if(num<=mid)
		update(num,tree[k].l,l,mid);
	else
		update(num,tree[k].r,mid+1,r);
}
 
int query(int i,int j,int l,int r)
{
	int d=tree[tree[j].l].sum-tree[tree[i].l].sum;
	if(l==r)
		return l;
	int mid=l+r>>1;
	if(d<(mid-l+1))
		return query(tree[i].l,tree[j].l,l,mid);
	else
		return query(tree[i].r,tree[j].r,mid+1,r);
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	init();
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		int num;
		scanf("%d",&num);
		root[i]=root[i-1];
		update(num+1,root[i],1,n);
	}
	while(m--)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		if(l==1&&r==n)
			printf("%d\n",n);
		else
			printf("%d\n",query(root[l-1],root[r],1,n)-1);
	}








    return 0;
}

思维

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e5+100;

int mmin1[N],mmin2[N],a[N];

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	mmin1[0]=mmin2[n+1]=n;
	for(int i=1;i<=n;i++)
		mmin1[i]=min(mmin1[i-1],a[i]);
	for(int i=n;i>=1;i--)
		mmin2[i]=min(mmin2[i+1],a[i]);
	while(m--)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%d\n",min(mmin1[l-1],mmin2[r+1]));
	}














    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/108299236