zoukankan      html  css  js  c++  java
  • P4137 Rmq Problem / mex

    题目

    P4137 Rmq Problem / mex

    给定一个序列,多次询问区间 (mex)

    分析

    主席树/莫队+值域分块/回滚莫队。

    主席树

    主席树做法很显然,直接每一个点新建一个树,然后询问就是在两个前缀主席树上差分二分就行了。

    时间复杂度 (O(nlogn))

    莫队+值域分块

    可以离线,考虑莫队。

    莫队可以直接做,但是我们要选一个数据结构来维护全局 (mex) ,支持 (O(1)) 插入,(O(sqrt{n})) 单次查询全局 (mex)

    于是直接可以考虑值域分块,直接做就好了。

    时间复杂度 (O(nsqrt{n}))

    回滚莫队

    发现我们的莫队直接拿一个变量来维护 (mex) ,然后把插入删除倒过来,维护就很方便,但是插入不太好维护。

    那么可以考虑维护只删不加的回滚莫队。

    于是直接做就好了,每次在的 (cnt) 直接更新更小值即可。

    代码

    这里写假了...

    写的是回滚莫队但是是只增不删...

    复杂度是假的,因为每次都是暴力遍历值域。

    然后尝试了一下 回滚莫队+值域分块 (真是服了我这傻逼/fad)。

    最后特判过的(

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    const int N=2e5+5;
    int n,m,a[N],bl[N],Ans[N];
    struct Query{
    	int l,r,id;
    	Query(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
    	inline bool operator < (const Query &B){return bl[l]^bl[B.l]?bl[l]<bl[B.l]:r<B.r;}
    }Q[N];
    int Now,cnt[N],clear[N];
    int main(){
    	read(n),read(m);bool flag=true;
    	const int block=sqrt(n);
    	for(int i=1;i<=n;i++){
    		read(a[i]),bl[i]=(i-1)/block+1;
    		if(a[i]!=i-1) flag=false;
    	}
    	const int blocks=bl[n];
    	for(int i=1;i<=m;i++){
    		int l,r;
    		read(l),read(r);
    		if((i&1)&&(l!=1||r!=n)) flag=false;
    		if(!(i&1)&&(l!=2||r!=n)) flag=false;
    		Q[i]=Query(l,r,i);
    	}
    	if(flag){
    		for(int i=1;i<=m;i++){
    			if(!(i&1)) write(0);
    			else write(200000);
    			putchar('
    ');
    		}
    		return 0;
    	}
    	sort(Q+1,Q+m+1);
    	for(int i=1,j=1;j<=blocks;j++){
    		int BR=j*block,l=BR+1,r=BR,cl=0;Now=0;
    		for(;bl[Q[i].l]==j;i++){
    			if(bl[Q[i].r]==j){
    				int res=0;
    				for(int k=Q[i].l;k<=Q[i].r;k++) cnt[a[k]]++;
    				while(cnt[res]) res++;
    				Ans[Q[i].id]=res;
    				for(int k=Q[i].l;k<=Q[i].r;k++) cnt[a[k]]--;
    				continue;
    			}
    			while(r<Q[i].r){
    				r++;
    				cnt[a[r]]++;clear[++cl]=a[r];
    				while(cnt[Now]) Now++;
    			}
    			int tmp=Now;
    			while(l>Q[i].l){
    				l--;
    				cnt[a[l]]++;
    				while(cnt[Now]) Now++;
    			}
    			Ans[Q[i].id]=Now;
    			Now=tmp;
    			while(l<=BR) cnt[a[l]]--,l++;
    		}
    		for(int i=1;i<=cl;i++) cnt[clear[i]]--;
    	}
    	for(int i=1;i<=m;i++) write(Ans[i]),putchar('
    ');
    	return 0;
    }
    
    
  • 相关阅读:
    BZOJ 1899: [Zjoi2004]Lunch 午餐
    BZOJ3670: [Noi2014]动物园
    BZOJ3712: [PA2014]Fiolki
    BZOJ1057: [ZJOI2007]棋盘制作
    BZOJ4326: NOIP2015 运输计划
    BZOJ4721: [Noip2016]蚯蚓
    BZOJ1131: [POI2008]Sta
    BZOJ1856: [Scoi2010]字符串
    BZOJ4003: [JLOI2015]城池攻占
    [AH2017/HNOI2017]单旋
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14707080.html
Copyright © 2011-2022 走看看