zoukankan      html  css  js  c++  java
  • CodeForces

    带单点修改的莫队

    众所周知莫队处理的区间不可以修改,因为要离线排序暴力答案,如果中途有修改的话,排序前后区间不同,答案也就是错的,如果要使答案正确的话还需要将时间统一,例如上次计算的答案在某次修改之后的区间,而这次在修改之前,那么就要回到过去,取消修改的影响,反之相反。

    难点就在这啦,按照普通莫队,每次都要统一时间的话时间复杂度会多一维,必然超时。大佬们想出了一种办法去优化,就是用二维莫队,如每次询问 l , r 区间,在 l 分块的基础上再把 r 分块,在多一维的p按从小到大顺序,暴力方法就是上一段说的,大佬们说这个的时间复杂度大约是 n^5/3左右,还是很厉害的。

    然后就是一些细节

    1.分块的大小为总数2/3次方,一般莫队为1/2。

    2.带修改操作需要离散化和记录数量的点会变多,最好数组开原来的两倍。

    3.记录被修改的点的前值与后值时,如果有多次在同一位置,记录的两个点应是上一次修改被改为的值与这次修改后的值,而不是a[p]与这次修改后的值。(a数组指给你的区间的值,长度为n的那个)

    4.在记录时如改变了a数组的值,需要记录完后改回去,因为一般时间从0开始。

    5.排序规则对 l , r 分块排序,对时间正常排。

    这些细节都是我惨痛教训。

    例题:CodeForces - 940F

    题意:给一个长度n数组,a数组记录值,q次操作,两种操作,一种修改a+p位置的值,一种算 l , r 区间的值的个数的mex(mex指,如果有s个相等的数,那s是好的,然后你要输出最小的不好的。如mex=3,说明区间内有相等的数的个数为1的存在,为2的存在,为3的不存在)。

    代码:

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    
    int n,q,ans[200007],a[200007],b[200007],l,r,z,size,head,maze,ak[200007],num[200007],cnt[200007];
    vector<int>lsh,qans;
    
    struct madoka{
    	int l;
    	int r;
    	int p;
    }ho[200007],lin;
    vector<madoka>ma;
    
    bool cmp(madoka a1,madoka a2){
    	if(ak[a1.l]==ak[a2.l]){
    		if(ak[a1.r]==ak[a2.r]){
    			return a1.p<a2.p;
    		}
    		return ak[a1.r]<ak[a2.r];
    	}
    	return ak[a1.l]<ak[a2.l];
    }
    
    void dis(){
    	sort(lsh.begin(),lsh.end());
    	lsh.erase(unique(lsh.begin(),lsh.end()),lsh.end());
    	for(int i=1;i<=n;i++){
    		a[i]=lower_bound(lsh.begin(),lsh.end(),a[i])-lsh.begin()+1;
    	}
    	for(int i=1;i<=q;i++){
    		if(ho[i].p!=0){
    			ho[i].l=lower_bound(lsh.begin(),lsh.end(),ho[i].l)-lsh.begin()+1;
    			ho[i].r=lower_bound(lsh.begin(),lsh.end(),ho[i].r)-lsh.begin()+1;
    		}
    	}
    }
    
    void go(){
    	l=1,r=1;
    	int p=0;
    	cnt[num[a[r]]]--;
    	num[a[r]]++;
    	cnt[num[a[r]]]++;
    	for(int i=0;i<ma.size();i++){
    		while(r<ma[i].r){
    			r++;
    			cnt[num[a[r]]]--;
    			num[a[r]]++;
    			cnt[num[a[r]]]++;
    		}
    		while(r>ma[i].r){
    			cnt[num[a[r]]]--;
    			num[a[r]]--;
    			cnt[num[a[r]]]++;
    			r--;
    		}
    		while(l<ma[i].l){
    			cnt[num[a[l]]]--;
    			num[a[l]]--;
    			cnt[num[a[l]]]++;
    			l++;
    		}
    		while(l>ma[i].l){
    			l--;
    			cnt[num[a[l]]]--;
    			num[a[l]]++;
    			cnt[num[a[l]]]++;
    		}
    		while(p<ma[i].p){
    			p++;
    			if(ho[p].p==0)continue;
    			if(ma[i].l<=ho[p].p&&ma[i].r>=ho[p].p){
    				cnt[num[ho[p].l]]--;
    				num[ho[p].l]--;
    				cnt[num[ho[p].l]]++;
    				cnt[num[ho[p].r]]--;
    				num[ho[p].r]++;
    				cnt[num[ho[p].r]]++;
    			}
    			a[ho[p].p]=ho[p].r;
    		}
    		while(p>ma[i].p){
    			if(ho[p].p==0){
    				p--;
    				continue;
    			}
    			if(ma[i].l<=ho[p].p&&ma[i].r>=ho[p].p){
    				cnt[num[ho[p].l]]--;
    				num[ho[p].l]++;
    				cnt[num[ho[p].l]]++;
    				cnt[num[ho[p].r]]--;
    				num[ho[p].r]--;
    				cnt[num[ho[p].r]]++;
    			}
    			a[ho[p].p]=ho[p].l;
    			p--;
    		}
    		for(int j=1;j<=n;j++){
    			if(cnt[j]==0){
    				ans[ma[i].p]=j;
    				break;
    			}
    		}
    	}
    }
    
    int main(){
    	scanf("%d%d",&n,&q);
    	size=(int)pow(n,2.0/3.0);
    	maze=ceil((double)n/size);
    	for(int i=1;i<=maze;i++){
    		for(int j=head;j<head+size&&j<=n;j++){
    			ak[j]=i;
    		}
    		head+=size;
    	}
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		b[i]=a[i];
    		lsh.push_back(a[i]);
    	}
    	for(int i=1;i<=q;i++){
    		scanf("%d%d%d",&z,&l,&r);
    		if(z==1){
    			lin.l=l;
    			lin.r=r;
    			lin.p=i;
    			ma.push_back(lin);
    			qans.push_back(i);
    		}
    		else{
    			lin.l=a[l];
    			lin.r=r;
    			lin.p=l;
    			ho[i]=lin;
    			a[l]=r;
    			lsh.push_back(r);
    		}
    	}
    	for(int i=1;i<=n;i++)a[i]=b[i];
    	dis();
    	sort(ma.begin(),ma.end(),cmp);
    	go();
    	for(int i=0;i<qans.size();i++){
    		printf("%d
    ",ans[qans[i]]);
    	}
    }
    
  • 相关阅读:
    centos npm run build 报错
    python base64
    Emacs 常用命令
    linux 删除文件腾出空间 遇到的问题
    网速查看工具
    linux 查看当前文件夹下的文件大小
    Docker 私有仓库push
    Harbor:Http: server gave HTTP response to HTTPS client & Get https://192.168.2.119/v2/
    docker 私有仓库搭建
    linux 修改时间
  • 原文地址:https://www.cnblogs.com/whitelily/p/13200223.html
Copyright © 2011-2022 走看看