• 【Codeforces 896E】—Welcome home, Chtholly(分块)


    传送门

    这个东西线段树没啥好办法维护
    考虑分块
    对于每个块每个权值维护一个并查集并且维护一下sizsiz
    考虑一次修改
    如果一个整块值域>2x>2x
    就把[1,x][1,x]向上合并,再整体打上标记
    否则把[x+1,mx][x+1,mx]向下合并
    这样可以在O(x)O(x)的时间内把值域减小xx
    对于散块暴力重构
    复杂度O(nn+mn)O(nsqrt n+msqrt n)

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    inline char gc(){
        static char ibuf[RLEN],*ib,*ob;
        (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ob==ib)?EOF:*ib++;
    }
    #define gc getchar
    inline int read(){
        char ch=gc();
        int res=0,f=1;
        while(!isdigit(ch))f^=ch=='-',ch=gc();
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
        return f?res:-res;
    }
    #define ll long long
    #define re register
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    #define cs const
    #define bg begin
    inline void chemx(int &a,int b){a<b?a=b:0;}
    inline void chemn(int &a,int b){a>b?a=b:0;}
    cs int N=100005,M=355;
    int n,m,a[N],val[N],fa[N];
    int id[M][N],mx[M],mn[M],s[N];
    int bel[N],L[M],R[M],blo,cnt;
    inline int find(int x){
    	return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    inline void build(int x){
    	mn[x]=0;int maxn=0;
    	for(int i=L[x];i<=R[x];i++)fa[i]=i;
    	for(int i=L[x];i<=R[x];i++){
    		chemx(maxn,a[i]);
    		val[i]=a[i];
    		if(!id[x][val[i]])id[x][val[i]]=i,s[i]=1;
    		else fa[i]=id[x][val[i]],s[find(i)]++;
    	}
    	mx[x]=maxn;
    }
    inline void rebuild(int x,int l,int r,int k){
    	for(int i=L[x];i<=R[x];i++)
    		id[x][val[i]]=0,a[i]=val[find(i)]-mn[x];
    	for(int i=l;i<=r;i++)if(a[i]>k)a[i]-=k;
    	build(x);
    }
    inline void update(int l,int r,int k){
    	if(bel[l]==bel[r]){
    		rebuild(bel[l],l,r,k);return;
    	}
    	rebuild(bel[l],l,R[bel[l]],k);
    	rebuild(bel[r],L[bel[r]],r,k);
    	for(int x=bel[l]+1;x<bel[r];x++){
    		if(mx[x]-mn[x]>2*k){
    			for(int i=mn[x]+1;i<=mn[x]+k;i++){
    				if(!id[x][i])continue;
    				if(!id[x][i+k])id[x][i+k]=id[x][i],val[id[x][i]]=i+k,id[x][i]=0;
    				else s[id[x][i+k]]+=s[id[x][i]],fa[id[x][i]]=id[x][i+k],id[x][i]=0;
    			}
    			mn[x]+=k;
    		}
    		else{
    			for(int i=mn[x]+k+1;i<=mx[x];i++){
    				if(!id[x][i])continue;
    				if(!id[x][i-k])id[x][i-k]=id[x][i],val[id[x][i]]=i-k,id[x][i]=0;
    				else s[id[x][i-k]]+=s[id[x][i]],fa[id[x][i]]=id[x][i-k],id[x][i]=0;
    			}
    			while(!id[x][mx[x]])mx[x]--;
    		}
    	}
    }
    inline int query(int l,int r,int k){
    	int res=0;
    	if(bel[l]==bel[r]){
    		for(int i=l;i<=r;i++)if(val[find(i)]-mn[bel[l]]==k)res++;
    		return res;
    	}
    	for(int i=l;i<=R[bel[l]];i++)
    		if(val[find(i)]-mn[bel[l]]==k)res++;
    	for(int i=L[bel[r]];i<=r;i++)
    		if(val[find(i)]-mn[bel[r]]==k)res++;
    	for(int i=bel[l]+1;i<bel[r];i++)
    		if(mn[i]+k<=mx[i])res+=s[id[i][mn[i]+k]];
    	return res;
    }
    int main(){
    	n=read(),m=read();
    	blo=sqrt(n),cnt=(n-1)/blo+1;
    	for(int i=1;i<=n;i++)a[i]=read();
    	for(int i=1;i<=n;i++)bel[i]=(i-1)/blo+1;
    	for(int i=1;i<=cnt;i++)L[i]=(i-1)*blo+1,R[i]=min(i*blo,n);
    	for(int i=1;i<=cnt;i++)build(i);
    	while(m--){
    		int op=read(),l=read(),r=read(),k=read();
    		if(op==1){
    			update(l,r,k);
    		}
    		else{
    			cout<<query(l,r,k)<<'
    ';
    		}
    	}
    }
    
  • 相关阅读:
    PHP 数组函数分类整理
    mysql 数据库中 int(3) 和 int(11) 有区别么???
    理解PHP的运行机制
    类与对象
    PHP函数补完:call_user_func()
    linux 软件安装目录详解
    Linux下安装Redis
    Redis简介,应用场景,优势
    idea自动抽取变量快捷键设置
    全局捕获异常(适用于SpringMvc,SpringBoot项目)
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328543.html
Copyright © 2020-2023  润新知