• P5906 【模板】回滚莫队&不删除莫队


    题目

    P5906 【模板】回滚莫队&不删除莫队

    回滚莫队

    回滚莫队是拿来干什么的呢?——在我们维护的数据不好删除,但是可以撤销,比较好添加的时候就可以使用回滚莫队来维护。

    (同样反过来也是,但是好删除不好添加应该很少见吧。/fad)

    那么具体怎么做的呢?

    首先认清楚裸回滚莫队的效率:大常数 (O(nsqrt{n})) ,就是跑满了的 (nsqrt{n})

    然后看一下具体实现:

    对于普通莫队,我们在什么情况下会有删除?——右端点每次回到左边或者左端点在块内移动的时候。

    那么对于那个右端点我们可以怎么处理让他不删除呢?很简单,对于每一个左端点的块,我们都重新清空来做一遍莫队即可,也就是重构。

    那么我们在什么情况下还会有删除?——在移动左端点的时候。(因为现在右端点只会不断递增了)

    于是我们可以这样考虑:在每次移动完当前的左端点过后,把它重新撤回到左端点在最右边的状态,那么相当于我们每一次都是在从右往左走然后撤回回去右端,这样做就没有删除了。

    具体实现的话,我们可以对于区间在 (sqrt{n}) 内的直接暴力处理,然后对于剩下的再用我们上述方法处理。

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

    分析

    这道题就是回滚莫队的板子题。

    首先我们考虑怎么维护这个信息,我们可以维护当前区间的每一个值的最左端和最右端,然后注意讨论一下几种情况就可以了。

    代码:

    #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;
    #define ll long long
    int n,m,k,a[N];
    int Ans[N],st[N],ed[N],b[N],cl,clear[N],bl[N],block,blo;
    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)const{return bl[l]!=bl[B.l]?bl[l]<bl[B.l]:r<B.r;}
    }Q[N];
    int las[N];
    int Calc(int l,int r){
    	int res=0;
    	for(int i=l;i<=r;i++) las[a[i]]=0;
    	for(int i=l;i<=r;i++) if(las[a[i]]) res=max(res,i-las[a[i]]); else las[a[i]]=i;
    	return res;
    }
    int main(){
    	read(n);
    	const int t=sqrt(n);
    	for(int i=1;i<=n;i++) read(a[i]),b[i]=a[i],bl[i]=(i-1)/t+1;
    	blo=bl[n];
    	sort(b+1,b+n+1);
    	int Id=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+Id+1,a[i])-b;
    	read(m);
    	for(int i=1;i<=m;i++){
    		int l,r;read(l),read(r);
    		Q[i]=Query(l,r,i);
    	}
    	sort(Q+1,Q+m+1);
    	for(int i=1,j=1;j<=blo;j++){
    		int R=min(j*t,n),l=R+1,r=R,now=0;cl=0;
    		for(;bl[Q[i].l]==j;i++){
    			if(bl[Q[i].r]==j){
    				Ans[Q[i].id]=Calc(Q[i].l,Q[i].r);
    				continue;
    			}
    			while(r<Q[i].r){
    				r++;
    				ed[a[r]]=r;
    				if(!st[a[r]]) st[a[r]]=r,clear[++cl]=a[r];
    				now=max(now,r-st[a[r]]);
    			}
    			int tmp=now;
    			while(l>Q[i].l){
    				l--;
    				if(!ed[a[l]]) ed[a[l]]=l;
    				now=max(now,ed[a[l]]-l);
    			}
    			Ans[Q[i].id]=now;
    			while(l<=R){
    				if(ed[a[l]]==l) ed[a[l]]=0;
    				l++;
    			}
    			now=tmp;
    		} 
    		for(int k=1;k<=cl;k++) st[clear[k]]=ed[clear[k]]=0;
    	}
    	for(int i=1;i<=m;i++) write(Ans[i]),putchar('
    ');
    	return 0;
    } 
    
  • 相关阅读:
    php连接mySql数据库 示例
    javascript Worker子线程
    js + php服务器推送see(自定义推送时间)
    javascript js获取html元素各种距离方法
    javascript 浅复制 和 深复制
    javascript 对象api
    php 搭建webSocket
    javascript 客户端webSocket示例
    javascript 集合 Object Array Map Set
    javascript json语句 与 js语句的互转
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14706353.html
Copyright © 2020-2023  润新知